串是由零個或多個字符組成的有限序列,又名叫字符串算法
串中的字符數目n稱爲串的長度數組
零個字符的串稱爲空串函數
一個結點能夠存儲一個字符也能夠考慮存儲多個字符,最後一個結點如果未被佔滿時,能夠用#或其它非串值字符補全google
對主串的每個字符做爲子串開頭,與要匹配的字符進行匹配。對主串作大循環,每一個字符開頭作T的長度的小循環,直到匹配成功或所有遍歷完成爲止。spa
時間複雜度爲O(n+m)3d
/* 返回子串T在主串S中第pos個字符以後的位置。若不存在,則函數返回值爲0。 */ /* 其中,T非空,1≤pos≤StrLength(S)。 */ int Index(String S, String T, int pos) { int i = pos; /* i用於主串S中當前位置下標值,若pos不爲1,則從pos位置開始匹配 */ int j = 1; /* j用於子串T中當前位置下標值 */ while (i <= S[0] && j <= T[0]) /* 若i小於S的長度而且j小於T的長度時,循環繼續 */ { if (S[i] == T[j]) /* 兩字母相等則繼續 */ { ++i; ++j; } else /* 指針後退從新開始匹配 */ { i = i-j+2; /* i退回到上次匹配首位的下一位 */ j = 1; /* j退回到子串T的首位 */ } } if (j > T[0]) return i-T[0]; else return 0; }
利用上面的算法,假設咱們要從主串goodgoogle中找到google,則須要下面的步驟指針
想一想若是咱們要在主串S="00000000000000000000000000000000000000000000000000001",而要匹配的子串T=「0000000001」code
也就是說T串須要在S串的前40個位置都須要判斷10次並獲得不匹配的結論,直到第41位才所有匹配相等blog
所以最壞的狀況的時間複雜度爲O(((n-m)+1)*m)字符串
若是主串S="abcdefgab",要匹配的子串T="abcdex"
若是用樸素算法的話,則匹配的流程圖以下所示:
細想一下,子串T中「abcdex」 首字母a與後面的串「bcdex」中的任意一個字符都不相等,既然a不與本身後面的子串中任何一個字符相等,那麼對於上圖1來講,前五個字符分別相等,意味着子串T的首字符a不可能與s串的第2位到第5位的字符相等,也就是說在上圖中二、三、四、5的判斷都是多餘的。
若是子串T中有與首字符相等的字符,也是能夠省略一部分沒必要要的判斷步驟的。
咱們把T串各個位置的j值的變化定義爲一個數組next,那麼next的長度就是T串的長度
/* 經過計算返回子串T的next數組。 */ void get_next(String T, int *next) { int i,j; i=1; j=0; next[1]=0; while (i<T[0]) /* 此處T[0]表示串T的長度 */ { if(j==0 || T[i]== T[j]) /* T[i]表示後綴的單個字符,T[j]表示前綴的單個字符 */ { ++i; ++j; next[i] = j; } else j= next[j]; /* 若字符不相同,則j值回溯 */ } } /* 返回子串T在主串S中第pos個字符以後的位置。若不存在,則函數返回值爲0。 */ /* T非空,1≤pos≤StrLength(S)。 */ int Index_KMP(String S, String T, int pos) { int i = pos; /* i用於主串S中當前位置下標值,若pos不爲1,則從pos位置開始匹配 */ int j = 1; /* j用於子串T中當前位置下標值 */ int next[255]; /* 定義一next數組 */ get_next(T, next); /* 對串T做分析,獲得next數組 */ while (i <= S[0] && j <= T[0]) /* 若i小於S的長度而且j小於T的長度時,循環繼續 */ { if (j==0 || S[i] == T[j]) /* 兩字母相等則繼續,與樸素算法增長了j=0判斷 */ { ++i; ++j; } else /* 指針後退從新開始匹配 */ j = next[j];/* j退回合適的位置,i值不變 */ } if (j > T[0]) return i-T[0]; else return 0; }
上面get_next的時間複雜度爲O(m),而index_KMP中while循環的時間複雜度爲O(n),因此整個算法的時間複雜度爲O(n+m)
好比主串S="aaaabcde",子串T="aaaaax",那麼next數組值分別爲012345
利用KMP算法比較的過程以下圖所示:
當i=5,j=5時,b與a不相等,如上圖1
j=next[5]=4,如上圖2,b與第四個位置的a依然不等
j=next[4]=3,如上圖3,...
細想一下,二、三、四、5步驟都是多餘的,由於T串的第2、3、4、五位置的字符都與首位a相等,那麼能夠利用首位的next[1]的值去取代與它相等的字符後續的next[j]的值
/* 求模式串T的next函數修正值並存入數組nextval */ void get_nextval(String T, int *nextval) { int i,j; i=1; j=0; nextval[1]=0; while (i<T[0]) /* 此處T[0]表示串T的長度 */ { if(j==0 || T[i]== T[j]) /* T[i]表示後綴的單個字符,T[j]表示前綴的單個字符 */ { ++i; ++j; if (T[i]!=T[j]) /* 若當前字符與前綴字符不一樣 */ nextval[i] = j; /* 則當前的j爲nextval在i位置的值 */ else nextval[i] = nextval[j]; /* 若是與前綴字符相同,則將前綴字符的 */ /* nextval值賦值給nextval在i位置的值 */ } else j= nextval[j]; /* 若字符不相同,則j值回溯 */ } }
(具體分析圖以下所示:
)
另一個例子(看看你推導正確了沒)