串的基本概念
串(或字符串),是由零個或多個字符組成的有窮序列。含零個字符的串稱爲空串,用Ф表示。
串中所含字符的個數稱爲該串的長度(或串長)。
當且僅當兩個串的長度相等而且各個對應位置上的字符都相同時,這兩個串纔是相等的。
一個串中任意個連續字符組成的子序列(含空串,但不含串自己)稱爲該串的子串。例如,「a」、「ab」、「abc」和「abcd」等都是「abcde」的子串(平凡子串不包括自身)。
問題: 「abcde」有多少個平凡子串?
解: 空串數:1
含1個字符的子串數:5
含2個字符的子串數:4
含3個字符的子串數:3
含4個字符的子串數:2
共有1+2+3+4+5=15個子串。
串的存儲結構
串的順序存儲及其基本操做實現
串是一種特殊的線性表,在非緊縮格式中,它的每一個結點僅由一個字符組成,所以存儲串的方法也就是存儲線性表的通常方法。存儲串最經常使用的方式是採用順序存儲,即把串的字符順序地存儲在內存一片相鄰的空間,這稱爲順序串。
串的非緊縮格式(一個單元存放一個字符)與串的緊縮格式(一個單元存放多個字符) ... ...
順序存儲採用通常順序表的存儲結構,其類型定義以下:node
其中,ch域用來存儲字符串,len域用來存儲字符串的當前長度,MaxSize常量表示容許所存儲字符串的最大長度。在C語言中每一個字符串以'\0'標誌結束(在這個結構體中不須要用'\0'標誌結束,如下標爲0開始存入字符)。
ASCII比較字符串
因爲 "大寫字母<小寫字母" ,而且a<b,所以在比較時ASCII大的字母比較靠前,但要特殊考慮大小寫夾雜的狀況
串的鏈式結構存儲
鏈式方式存儲串,即用單鏈表形式存儲串。這稱爲鏈式串或鏈串。
鏈串中的結點類型定義:算法
例:在鏈串中,設計一個算法把最早出現的子串"ab"改成"xyz"。
解:在串s中找到最早出現的子串"ab",p指向data域值爲'a'的結點,其後爲data域值爲'b'的結點。將它們的data域值分別改成'x'和'z',再建立一個data域值爲'y'的結點,將其插入到*p以後。本例算法以下:數組
擴展,編寫一個算法實現替換字符串(提示:查找(串的模式匹配,見下面的介紹)、替換相結合)
--------------------------------------------------------
重點:
串的模式匹配————(本人認爲較難,很難很難,不過絕對值得一學,學會了有成就感
設有主串s和子串t,子串t的定位就是要在主串s中找到一個與子串t相等的子串。一般把主串s稱爲目標串,把子串t稱爲模式串,所以定位也稱做模式匹配。模式匹配成功是指在目標串s中找到一個模式串t;不成功則指目標串s中不存在模式串t。
算法一:BF算法(Brute-Force)
Brute-Force簡稱爲BF算法,亦稱簡單匹配算法,其基本思路是:
從目標串s="s0s1…sn-1"的第一個字符開始和模式串t="t0t1…tm-1"中的第一個字符比較,若相等,則繼續逐個比較後續字符;不然從目標串s的第二個字符開始從新與模式串t的第一個字符進行比較。依次類推,若從模式串s的第i個字符開始,每一個字符依次和目標串t中的對應字符相等,則匹配成功,該算法返回i;不然,匹配失敗,函數返回-1。
一種實現:函數
二種實現:lua
上面這兩個算法都不怎麼難理解~~
關鍵是下面這個KMP模式匹配算法:
算法二:
現在呢我也是,似懂非懂,半懂加不懂~~~
固然裏面最重要的一步就是求next數組~~~
next數組的功能是,字符串在匹配失效時,主串不用再向前作回溯操做即沒有 i=i-j+1; 這步
而只對模式串作右滑操做,到底右滑多少,由next對應模式失配的下標決定。
而相應next數組的產生只取決模式自身,其證實亦很簡單
關鍵是如何獲得next數組。。。。spa
串的操做實現代碼以下:設計
//串的順序存儲.. //結構體定義.. #include<stdio.h> #define MAX 100 typedef struct { char S[MAX]; }SString; //串的初始化.. void Init_Str(SString &SS) { for(int i=0;i<MAX;i++) { SS.S[i]='\0'; //把全部值都賦'\0'.. } } //求串的長度.. int Length_Str(SString SS) { int length=0; while(SS.S[length]!='\0') //不是'\0'的話就累加起來,知道最後就知道了長度.. { length++; } return length; } //串的賦值.. void StrEvaluate(SString &SS,char S1[]) { for(int i=0;S1[i]!='\0';i++) //這語句前面能夠初始化一下SS.S[]也行.. { SS.S[i]=S1[i]; } } //串的連接.. void StrConcat(SString &SS,SString &S1) { int len1,len2; len1=Length_Str(SS); len2=Length_Str(S1); if(len1+len2+1<MAX) { for(int i=0;i<len2;i++) { SS.S[len1+i]=S1.S[i]; } } else { printf("你輸入的字符串長度超過了MAX!!!"); } } //求串的字串.. SString SubStr(SString &SS,int i,int length) //SS的第i個位置開始去length長的字串..而後返回.. { SString S1; Init_Str(S1); if(i+length<Length_Str(SS)) //判斷字串的長度是否合法.. { for(int j=i;j<=i+length;j++) { S1.S[j-i]=SS.S[j]; } } else { printf("所取的length超出主串的長度!!!"); } return S1; } //串的比較.. int StrComp(SString S1,SString S2) { int i=0; while(S1.S[i]==S2.S[i]&&S1.S[i]!='\0') //第一個元素開始判斷是否相等..不相等的話來判斷那個大那個小.. { i++; } if(S1.S[i]==S2.S[i]) { return 0; } else if(S1.S[i]>S2.S[i]) { return 1; } else { return -1; } } //主函數.. int main() { int k=0,len=0; SString SS,S1,S2,S3; char ch1[20]={'a','b','c','d','e','f'}; char ch2[20]={'k','l','n','m','j','k'}; char ch3,ch4,ch5,ch6,ch7,ch8,ch9; char flag=1,flag1=1; while(flag) { printf("**************************************\n"); printf("*\t1 初始化串\n"); printf("*\t2 求串的長度\n"); printf("*\t3 串的賦值\n"); printf("*\t4 串的連接\n"); printf("*\t5 求字串\n"); printf("*\t6 串的比較\n"); printf("*\t11 推出程序\n"); printf("**************************************\n"); scanf("%c",&ch3); switch(ch3) { case '1': while(flag1) { printf("\t---------------\n"); printf("-\t1. SS初始化\n"); printf("-\t2. S1初始化\n"); printf("-\t3. S2初始化\n"); printf("\t---------------\n"); scanf("%c",&ch4); switch(ch4) { case '1': Init_Str(SS); printf("SS初始化成功!"); break; case '2': Init_Str(S1); printf("S1初始化成功!"); break; case '3': Init_Str(S2); printf("S2初始化成功!"); break; case '4': flag1=0; printf("renyijian!!"); //default: } getchar(); } case '2': printf("\t---------------\n"); printf("-\t1. 求SS長度\n"); printf("-\t2. 求S1長度\n"); printf("-\t3. 求S2長度\n"); printf("\t---------------\n"); scanf("%c",&ch5); switch(ch5) { case '1': len=Length_Str(SS); printf("SS長度=%d",len); break; case '2': len=Length_Str(S1); printf("S1長度=%d",len); break; case '3': len=Length_Str(S2); printf("S2長度=%d",len); break; default: printf("changdu\n"); } case '3': while(flag) { printf("\t---------------\n"); printf("-\t1. SS賦值\n"); printf("-\t2. S1賦值\n"); printf("-\t3. S2賦值\n"); printf("\t---------------\n"); scanf("%c",&ch6); switch(ch6) { case '1': StrEvaluate(SS,ch1); printf("SS賦值成功\n!"); break; case '2': StrEvaluate(S1,ch2); printf("S1賦值成功\n!"); break; case '3': StrEvaluate(S2,ch1); printf("S2賦值成功\n!"); break; //default: //printf("fuzhi\n"); } getchar(); } case '4': printf("\t---------------\n"); printf("-\t1. SS和S1連接\n"); printf("-\t2. SS和S2連接\n"); printf("-\t3. S1和S2連接\n"); printf("\t---------------\n"); scanf("%c",&ch7); switch(ch7) { case '1': StrConcat(SS,S1); printf("SS和S1連接成功!"); break; case '2': StrConcat(SS,S2); printf("SS和S2連接成功!"); break; case '3': StrConcat(S1,S2); printf("S2和S1連接成功!"); break; default: printf("lianjie\n"); } case '5': printf("\t---------------\n"); printf("-\t1. SS的字串\n"); printf("-\t2. S1的子串\n"); printf("-\t3. S2的子串\n"); printf("\t---------------\n"); scanf("%c",&ch8); switch(ch8) { case '1': S3=SubStr(SS,3,3); break; case '2': S3=SubStr(S1,3,3); break; case '3': S3=SubStr(S2,3,3); break; default: printf("zichuan\n"); } case '6': printf("\t---------------\n"); printf("-\t1. SS和S1比較\n"); printf("-\t2. SS和S2比較\n"); printf("-\t3. S1和S2比較\n"); printf("\t---------------\n"); scanf("%c",&ch9); switch(ch9) { case '1': k=StrComp(SS,S1); printf("%d",k); printf("SS和S1比較成功!"); break; case '2': k=StrComp(SS,S2); printf("%d",k); printf("SS和S2比較成功!"); break; case '3': k=StrComp(S1,S2); printf("%d",k); printf("S2和S1比較成功!"); break; default: printf("比較\n"); } case '11': flag=0; printf("任意鍵結束程序.."); } getchar(); } return 0; }