第四章:1.串 -- 串類型定義及串的表示和實現


前言:

  計算機上的應用程序幾乎都是以字符串數據作為處理對象,然而,現今我們使用的計算機的硬件結構主要是反映數值計算的需要的,因此,在處理字符串數據時比處理整數和浮點數要復雜得多。而且,在不同類型的應用中,所處理的字符串具有不同的特點,要有效地實現字符串的處理,就必須根據具體情況使用合適的存儲結構。這一章,我們將討論一些基本的串處理操作 和 幾種不同的存儲結構。

 

目錄:

  1.串類型的定義

  2.串的表示和實現

    2.1.定長順序存儲表示

    2.2.堆分配存儲表示

    2.3.串的塊鏈存儲表示

  3.串的模式匹配算法

  4.串操作應用劇烈

 

正文:

  串類型的定義

  串(string)(或字符串)是由 零個或多個字符 組成的有限序列,一般記為:

      s=' a1a2...an '

  注意:由一個或多個空格組成的串,稱為空格串。而不是空串。

    

    串 和 字符序列(char * ='hello')的區別:

      串是一種數據結構,是字符的集合,實現並提供對這種集合操作的各種方法。

      char 是c 的一種基本數據類型,沒有已實現的對字符序列的復雜操作。

 

  串的邏輯結構和線性表極為相似,區別在於:

    1.串的數據對象約束為字符集。

    2.在線性表的基本操作中,以“單個數據元素” 為操作對象。 在串中 以 “串的整體” 作為操作對象,例如:查找子串、插入及刪除子串。

 

  串的表示及實現

    串有3種機內表示方法:

    1.定長順序存儲 表示

      類似於線性表的順序存儲結構,用一組地址連續的存儲單元存儲串值的字符序列。在串的定長順序存儲結構中,按照預定義的大小,為每個定義的串變量分配一個固定長度的存儲區,則可用定長數組如下描述之。

 

      存儲表示:

        #define MAXSTRLEN 255                 //定義最大串長

        typedef  unsigned char SString [MAXSTRLEN +1];    //0單元存放串的長度

 

      串的實際長度可在這預定義長度的范圍內隨意, 超出的部分被舍棄,稱之為 “截斷” 。

 

      弊端:當合並兩個 串的時候,如果長度超過 預定義最大串長MAXSTRLEN ,其它部分將會丟失即 “截斷”。

 

      解決方案:使用不限定串長的最大長度, 即動態分配串值的存儲空間。

 

    2.堆分配存儲表示

      特點:仍以一組地址連續的存儲單元存放串值字符序列,但它們的存儲空間是在程序執行過程中動態分配而得。

      在 C 語言中,存在一個稱之為 “堆” 的自由存儲區, 並由C 語言的動態分配函數 malloc() 和 free()來管理。利用malloc 函數為每個新產生的串分配一塊實際串長所需的存儲空間,若分配成功,則返回一個指向起始地址的指針,作為串的基址,同時,為了處理方便,約定串長也作為存儲結構的一部分。

 

      堆分配存儲表示:

        typedef struct {

          char *ch;          //若是非空串,則按串長分配存儲區,否則 ch 為 NULL

          int  length;         // 串長度

        }HSring;

 

      代碼實現:

#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

#define MAXQSIZE 5
//Status是函數的類型,其值是函數結果狀態碼
typedef int Status;

typedef struct{
    char *ch;                    //若是非空串,則按串長分配存儲區,否則 ch 為 NULL
    int length;                    //字符串長度
}HString;

//生成一個其值等於串常量 chars  的串T
Status StrAssign(HString &S,char * chars){
    int i;
    for(i=0;chars[i];i++){}
    //if(S.ch){
    //    free(S.ch);
    //    S.ch=NULL;
    //}
    if(!i){
        S.ch=NULL;
        S.length=0;
    }else{
        S.ch=(char *)malloc(i*sizeof(char));
        if(!S.ch) exit(OVERFLOW);
        S.length=i;
        for(int j=0;j<i;j++)
            S.ch[j]=chars[j];
    }
    return OK;
}

//返回串長度
int StrLength(HString &S){
    return S.length;
}

//比較大小,若 S>T 返回值>0。相等 返回0 ,否則返回 <0
int StrCompare(HString S,HString T){
    for(int i=0;i<S.length&&i<T.length;i++){
        if(S.ch[i]!=T.ch[i])
            return S.ch[i]-T.ch[i];
    }
    return S.length-T.length;
}

//清空串S為空串,並釋放所占空間
Status ClearString(HString &S){
    if(S.ch){
        free(S.ch);
        S.ch=NULL;
    }
    S.length=0;
    return OK;
}

//連接兩個字符串,生成一個新的字符串
Status Concat(HString &T,HString S1,HString S2){
    //if(T.ch) free(T.ch);
    T.ch=(char *)malloc((S1.length+S2.length)*sizeof(char));
    if(!T.ch) exit(OVERFLOW);
    T.length=S1.length+S2.length;
    for(int i=0;i<S1.length;i++)
        T.ch[i]=S1.ch[i];

    for(i=0;i<S2.length;i++)
        T.ch[i+S1.length]=S2.ch[i];

    return OK;
}

//字符串截取,返回截取的串
Status SubString(HString &sub,HString S,int pos,int len){
    if(pos<1||pos>S.length||len<0||(S.length-pos+1)<len)
        return ERROR;
    //if(sub.ch) free(sub.ch);
    sub.ch=(char *)malloc(len*sizeof(char));    
    if(!sub.ch) exit(OVERFLOW);
    for(int i=0;i<len;i++)
        sub.ch[i]=S.ch[i+pos-1];
    sub.length=len;
    return OK;
}

void printV(HString &S){
    for(int i=0;i<S.length;i++){
        printf("地址:%p,",&S.ch[i]);
        printf("值:%c\n",S.ch[i]);    
    }    
}

void prints(HString &S){
    for(int i=0;i<S.length;i++){        
        printf("%c",S.ch[i]);    
    }    
    printf("%s\n"," ");
}

void main(){
    HString S1;
    char *c="hello";    
    StrAssign(S1,c);
    ClearString(S1);
    c="hello";    
    StrAssign(S1,c);
    printf("%s","S1:");
    prints(S1);
    printV(S1);

    HString S2;
    c="China";    
    StrAssign(S2,c);
    printf("%s","S2:");
    prints(S2);
    printV(S2);

    HString T;
    Concat(T,S1,S2);
    printf("%s","T:");
    prints(T);
    printV(T);

    HString sub;
    SubString(sub,T,6,5);
    printf("%s","sub:");
    prints(sub);
    printV(sub);
}

 

      運行結果:

           

 

  串的表示和實現

    串的塊鏈存儲表示:

    和線性表的鏈式存儲表示相似,串也可以采用鏈表方式存儲串值。由於串結構的特殊性,存儲時一個結點可以存放一個字符也可以存放多個字符。

    當結點大小大於1時,由於 串值可能不是結點大小的整數倍,則鏈表最后一個結點可能無法填滿,此時通常補上 “#” 或其他非串值 字符。如下圖:

    

    定義:

      為了便於進行串的操作,當以鏈表存儲串值時,除頭指針外還可附設一個尾指針指示鏈表中的最后 一個結點,並給出當前串的長度,稱如此定義的串存儲結構為塊鏈結構。

     

    串的塊鏈存儲表示

    #define CHUNKSIZE  80;          //結點大小,用戶自己隨便定義

    typedef struct Chunk{           //結點定義

      char ch[CHUNKSIZE];

      struct Chunk *next;

    }Chunk;

    typedef struct{

      Chunk *head,*tail;      //串的頭指針,和尾指針

      int  curlen;          //串的長度

    }

    注:設置尾指針的目的是 便於進行串的連接操作,但要注意連接時需處理第一個串尾的無效字符(#)。

 

   鏈式串中,結點的大小直接影響着串處理的效率。

      存儲密度 = 串值所占的存儲位 / 實際分配的存儲位  

    對於固定的串a ,其串值存儲位是固定的,而實際分配的存儲位根據結點的大小而改變。

    顯然當存儲密度最小時,(即結點大小為1)串的運算處理最方便,但是其占用的存儲量大。

 

  總結:

    串的鏈式存儲,對鏈接操作等有一定的方便之處, 但總的來說不如另外兩種結構靈活,它占用存儲量大且操作復雜。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM