KMP演算法筆記關於KMP
(1)
引子:
對於2個字串A,B,其中A為主串,B為待匹配的子串,如
i 1
2 3 4 5 6 7 8 ...
A:a b a a c c a b a b a
a b c a c b a c a c ...
B:a b a a b c a c
j 1
2 3 4 5 6 7 8 ...
當A[5] != B[5]時,蠻力法是從頭再來,而KMP演算法則不同,它採用一定的策略,調整j的位置,使得B[j] == A[i]。
(2)
KMP主代碼:
int KMPSearch(const char * main_str, const char * sub_str, int * next)<br />{<br /> int i=0;<br /> int j=0;<br /> int main_len=strlen(main_str);<br /> int sub_len=strlen(sub_str);</p><p> while((i<main_len)&&(j<sub_len))<br /> {<br /> if(j == -1 || main_str[i] == sub_str[j]) {<br /> j++;<br /> i++;<br /> }else{<br /> j=next[j];<br /> }<br /> }</p><p> if(j == sub_len){<br /> return i-sub_len;<br /> }else{<br /> return -1;<br /> }<br />}
(3)從(2)中的代碼可以看出,KMP演算法的關鍵是構造next表。
關於next
1 next[i]表示的是:
在第i個字元前面的i-1個字元裡面,
從開頭開始的1個字元與最後1個字元是否相等,若不是,則next[i]=0,否則繼續看下面;
從開頭開始的2個字元與最後2個字元是否相等,若不是,則next[i]=1,否則繼續看下面;
從開頭開始的3個字元與最後3個字元是否相等,若不是,則next[i]=2,否則繼續看下面;
……
2 next數組求解思路:
第1位的next值為-1,第2位的next值為0,後面求解每一位的next值時,根
據前一位進行比較。
比較策略如下:
(1)
將前一位與其(next值對應的字元)進行比較;
(2)
如果相等,則該位的next值就是前一位的next值加上1;
(3)
如果不等,向前繼續尋找(next值對應的字元)來與前一位進行比較;
(4)
如果最後找到,則在這個位對應的值加上1,即為所求的next值;
(5)
如果最後沒有找到,那麼所求next值為0。
3 next函數如下:
void CalculateNext(const char * sub_str, int len, char * next)<br />{<br /> int i=-1;<br /> int j=0;<br /> next[0]=-1;</p><p> while(j<len){<br /> //i == -1表示找到最後,策略(5)<br /> //sub_str[i] == sub_str[j]表示找到,策略(1)(2)<br /> if(i == -1 || sub_str[i] == sub_str[j]){<br /> //策略(2)(4)<br /> i++;<br /> j++;<br /> next[j]=i;<br /> }else{<br /> //策略(3)<br /> i=next[i];<br /> }<br /> }<br />}
KMP與DFA
附:
void CalculateNext(const char * sub_str, int len, int * next)<br />{<br />int i=-1;<br />int j=0;<br />next[0]=-1;<br />while(j<len){<br />if(i == -1 || sub_str[i] == sub_str[j]){<br />i++;<br />j++;<br />next[j]=i;<br />}else{<br />i=next[i];<br />}<br />}<br />}<br />int KMPSearch(const char * main_str, const char * sub_str)<br />{<br />int i=0;<br />int j=0;<br />int * next;<br />int main_len=strlen(main_str);<br />int sub_len=strlen(sub_str); </p><p>next = (int*)malloc(sizeof(int)*sub_len + 1);<br />CalculateNext(sub_str, sub_len, next);<br />while((i<main_len)&&(j<sub_len))<br />{<br />if(j == -1 || main_str[i] == sub_str[j]) {<br />j++;<br />i++;<br />}else{<br />j=next[j];<br />}<br />}<br />if(j == sub_len){<br />return i-sub_len;<br />}else{<br />return -1;<br />}<br />}<br />