字符串(簡稱串),可以將其看作是種特殊的線性表,其特殊性在於線性表的數據元素的類型總是字符性,字符串的數據對象紅豆為字符集。
串是由0個或多個字符組成的有限序列。一般記作:s = "s1 s2 s3 .... sn",,其中,s是串名,用雙引號括起來的字符序列稱為串的值,si(1<=i <= n)稱為串的元素,可以是字母,數字或其他字符,是構成串的基本單位,字符的個數n稱為串的長度.
1. 空串: 由0個字符組成的串稱為空串,空串不包含任何字符,其長度為0。
2. 子串: 串中任意個連續的字符組成的子序列稱為該串的子串,空串是任何串的子串。
3. 主串: 包含子串的串相應的稱為主串。
4. 子串在主串的位置:通常稱字符在序列中的序號為該字符在串的位置,子串在主串中的位置則以子串的第一個字符在主串中的位置來表示。
5. 兩串相等:當且僅當兩個串的長度相等,並且各個對應位置的字符都相等時才相等。
串的順序存儲結構簡稱為順序串,順序串中的字符序列被順序地存放在一組連續的存儲單元中,主要有三種實現順序串的方式,分別如下:
(1) 定長字符數組
在串的順序存儲結構中,按照預定義的大小,為每個定義的串變量分配一個固定大小的存儲區,描述如下:
//定長字符數組描述 #define MAXSIZE 100 typedef char SString[MAXSIZE];
(2) 帶串長的字符數組
//帶串長的字符數組 #define MAXSIZE 100 typedef struct{ char ch[MAXSIZE]; int length; }SqString;
//串的堆分配存儲描述 typedef struct{ char *ch; //若是非空串,則按串長分配存儲區,否則,ch為NULL int length; //串長度 }HString;
和線性表的鏈式存儲結構相類似,也可以采用鏈表方法存儲串值,有以下兩個方法:
(1)串的鏈式結構類型描述:
//串的鏈式存儲結構描述 typedef struct node{ char str; struct node *next; }CNode,*LinkString;
//串的塊鏈結構類型描述 #define NODESIZE 3 typedef struct node{ char ch[NODESIZE]; struct node *next; }SNode,*LinkStr; LinkStr head;
串也可以用索引的方式來表示,有以下兩種方法:
(1)串的帶長度的索引表:
//帶長度的索引表 #define MAXSIZE 100 typedef struct{ char name[MAXSIZE]; int length; char *startadr; }LSNode;
//串的帶末指針的索引表 #define MAXSIZE 100 typedef struct{ char name[MAXSIZE]; int length; char *startadr; char *endadr; }ENode;
以上介紹了三種存儲結構來表示串,每一種存儲結構又可以用幾種不同的方式來描述串,那麼,串的實現方法相應的也有多種,但不管有多少種,串的基本操作原理不變,變的只是處理的方式,所以也沒有必要將所有方式都學會,只要會一種即可,這裡就實現其中最常用動態數組來描述串,並以此種方式來實現口串的各種操作。
這裡所有的基本操作都是建立在上述的用動態數組,即堆結構來描述串的前提下的,直接給出代碼,裡面有注釋。
//串的堆分配存儲描述 typedef struct{ char *ch; //若是非空串,則按串長分配存儲區,否則,ch為NULL int length; //串長度 }HString; //初始化一個空的順序串 void Str_Init(HString *S){ S->ch = NULL; S->length = 0; } //清空順序串 void Str_Clear(HString *S){ if(S->ch){ free(S->ch); Str_Init(S); } } //判斷順序串是否為空 int Str_IsEmpty(HString *S){ return S->length == 0; } //求取串的長度 int Str_GetLength(HString *S){ return S->length; } //順序串的賦值 void Str_Assign(HString *S,char *chars){ int i = 0,j; char *c = chars; //先清空順序串S Str_Clear(S); //求得賦值串的長度 while(*c){ i++; c++; } //如果賦值串的長度大於0,則進行賦值 if(i > 0){ S->ch = (char*)malloc(3*sizeof(char)); for(j = 0;j < i;j++){ S->ch[j] = chars[j]; } S->length = i; } } //順序串的復制,將T復制到S void Str_Copy(HString *S,HString *T){ int i; //先清空順序串S Str_Clear(S); S->length = T->length; if(S->length){ S->ch = (char *)malloc(sizeof(char)*S->length); for(i = 0;i < S->length;i++) S->ch[i] = T->ch[i]; } } //順序串的連接,將T連接到S後 void Str_Concat(HString *S,HString *T){ //臨時存放S串 HString temp; int i,j; Str_Init(&temp); Str_Assign(&temp,S->ch); //清空S Str_Clear(S); //重新為S分配空間 S->length = temp.length + T->length; S->ch = (char*)malloc(sizeof(char) * S->length); //分別將temp和T依次賦值給S for(i = 0;i < temp.length;i++) S->ch[i] = temp.ch[i]; for(j = 0; j < T->length;j++) S->ch[i++] = T->ch[j]; //將temp釋放掉 free(temp.ch); } //順序串的比較,如果S>T,返回大於0的值,小於,則返回小於0的值 int Str_Compare(HString *S,HString *T){ int i; for(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; } //求子串並用Sub返回 void Str_GetSub(HString *S,int pos,int len,HString *Sub){ int i; //判斷位置和長度的合法性 if(pos < 1 || pos > S->length || len < 0 || len > S->length - pos + 1){ printf("子串的位置或長度不合法!\n"); exit(-1); } else{ Str_Clear(Sub); if(len){ Sub->ch = (char *)malloc(len * sizeof(char)); for(i = 0;i < len;i++) Sub->ch[i] = S->ch[pos + i -1]; Sub->length = len; } } } //在順序串中找出給定子串給定位置後出現的第一個的位置 int Str_GetSubIndex(HString *S,HString *Sub,int pos){ int i,j; //先判斷位置的合法性 if(pos < 1 || pos > S->length){ printf("位置不合法!\n"); exit(-1); } if(Str_IsEmpty(S)){ printf("順序串為空!\n"); return -1; } if(Str_IsEmpty(Sub)){ printf("給定子串為空,空串為任何串的子串!\n"); return 0; } for(i = pos - 1; i < S->length - Sub->length + 1;i++){ for(j = 0; j < Sub->length;j++) if(S->ch[i+j] != Sub->ch[j]) break; // 如果找到子串,則j= sub->length if(j == Sub->length) return i + 1; } //如果找不對,則返回-1; return -1; } //順序串中插入子串 void Str_Insert(HString *S,int pos,HString *T){ int i; HString temp; if(pos < 1 || pos > S->length){ printf("位置不合法!\n"); exit(-1); } if(Str_IsEmpty(T)){ printf("子串為空!\n"); exit(0); } Str_Init(&temp); temp.length = S->length + T->length; printf("%d\n",temp.length); temp.ch = (char *)malloc(sizeof(char)*temp.length); for(i = 0 ;i < pos ;i++) temp.ch[i] = S->ch[i]; for(; i < pos + T->length;i++) temp.ch[i] = T->ch[i - pos]; for(;i < temp.length;i++) temp.ch[i] = S->ch[i - T->length]; //將串S 清空,並將串temp賦值給S Str_Clear(S); S->ch = temp.ch; S->length = temp.length; } //在順序串刪除子串 void Str_DeleteSub(HString *S,int pos,int len){ int i; HString temp; //判斷位置和長度的合法性 if(pos < 1 || pos > S->length || len < 0 || len > S->length - pos + 1){ printf("子串的位置或長度不合法!\n"); exit(-1); } if(Str_IsEmpty(S)){ printf("順序串為空!\n"); exit(0); } Str_Init(&temp); temp.length = S->length - len; temp.ch = (char *)malloc(sizeof(char)*temp.length); for(i = 0 ;i < pos - 1; i++) temp.ch[i] = S->ch[i]; for(;i < temp.length;i++) temp.ch[i] = S->ch[i+len]; //將串S清空,並將串temp賦值給S Str_Clear(S); S->ch = temp.ch; S->length = temp.length; } //打印順序串 void Str_Print(HString *S){ int i = 0; if(Str_IsEmpty(S)){ printf("順序串為空!\n"); exit(0); } else printf("%s\n",S->ch); }