背景:在長串A中查找子串B
變量:i———->匹配的過程中,指向父串A待匹配的字符,是它的下標
j———>匹配的過程中,指向子串B待匹配的字符,也是下標
KMP算法介紹:
1.普通字符串匹配算法:這裏介紹兩種思路
先是和KMP對應的思路,也是嚴蔚敏書上講的思路——從左往右遍歷父串A,當A[i++]==B[j++]並完全匹配B時,i只要繼續向後移一位(++i)即可,j重新置0;當A[i++]和B[j++]在某個字符處失配時,要使i=i-j+1(即將i恢復成開始匹配的狀態並向後移動一位),j也要置0======>>此處也就產生了KMP算法要解決的問題:i的回溯
然後是我的想法(其實基本上完全一樣,寫在這裏是因爲比較一下讓自己印象更清楚)——大體同上,不同的是,匹配過程中i不向前移動,而是利用j的值比較A[i+j]和B[j++],完全匹配時,i=i+j(此時j已經爲子串B的長度);不匹配時只要使i++及j=0,這樣也就掩蓋了“i的回溯”這一問題:(
2.KMP算法講解:
對於父串和子串中有較多的重複字符來說,i的回溯將成爲比較嚴重的問題(特別是在子串較長的情況下),解決方法的思路在於:
如果在失配的時候父串已經和子串匹配了一部分(假設父串爲[0…20],已匹配的部分是[3…8],即開始匹配的字符下標是3,已經匹配了6個字符),那麼有可能[4…8]、[5…8]、[6…8]、[7…8]、[8]是匹配的(也可能那幾個都不匹配);不可能[4…6]是匹配的而[8]是不匹配的,這樣的父串並沒有匹配,因此沒必要繼續匹配。
所以i就不用回溯了,只要讓j爲它應該處在的位置即可,比如上面那幾個區間j分別對應5,4,3,2,1,0;如果兩串比較第一個字符的時候就失配,此時j不能爲子串的任何一個下標,不如讓它等於-1;一旦出現j==-1,需要++i,j=0——或者,更好爲++i,++j
==>>也就是說,失配的時候i不變,j要進行漂移,也就是要獲得j下一個值,我們用next數組存儲。next[j]表示下標爲j在失配時應該漂爲的下標
先給匹配函數:
void KMP(char *A, char *B, int *next, int alen, int blen){
int i=0, j=0;
while(i<alen){
if(j==0 || A[i]==B[j]){
++i, ++j;
}
else{
j=next[j];
}
}
}
再給next數組獲取函數:
void getNext(char *B, int *next, int blen){
int i=0, j=-1;//j=-1說明第一個字符就失配
next[0]=-1;
while(i<blen){
if(j==-1 || B[i]==B[j]){
++i, ++j;
next[i]=j;//這也是個關鍵點,表示[0...(j-1)]的字符與[(i-j-1)...(i-1)]是匹配的,當第i個字符失配時,將對父串[i]和子串[j]進行比較
}
else{
j=next[j];
}
}
}
對於證明還是不能很好理解,以後理解了再補吧。