KMP演算法的理解
阿新 • • 發佈:2019-02-04
什麼是KMP演算法?
模式串 char[] pat = new char[M]; 文字串 char[] txt = new char[N];
假設當前正在比較的字元是txt[i]和pat[j], 即pat[0, j - 1]已經匹配成功。txt[i]後面的字元處於未知狀態。
pat[j]之前的子字串的最長相同字首字尾的長度為k,即pat[0, k -1] 與pat[j – k, j – 1]依次在對應位上相等。
如果匹配失敗,則下一次比較的字元對是txt[i]和pat[k]。
可以看出,向右移動了j - k位。如果按照暴力查詢法,則只會移動1位。
next[]陣列的求解?
下面分析一下如果已知next[j]=k,如何推匯出next[j+1]。
求next[j+1]就是求字串pat[0,j]的最長字首字尾的長度。
1. 如果pat[k]==p[j],則next[j+1] = next[j] + 1 = k + 1;
1. 如果pat[k]≠p[j],暫時還不能確定,需進一步判斷。記next[k]的值為m,若pat[m] == pat[j],則next[j+1] = m + 1;否則繼續遞迴字首索引k = next[k],而後重複此過程,直到m=-1,表示匹配失敗,next[j+1] = 0。
記,如下圖。
注:
若next[k]=m, 則:
pat[0,m-1] = pat[k-m,k-1];
再根據next[j]=k,則
pat[k-m,k-1] = pat[k-m + (j-k),k-1+(j-k)] = pat[j-m,j-1],
從而得出結論:
pat最前面的m個字元和索引j之前的m個字元依次相等。
附求Next陣列的程式碼:
void GetNext(String p,int[] next) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { /*迴圈起始,k的值是子串a[0,j-1]的最大字首字尾長度,即next[j];為了計算a[0,j]的最大字首字尾長,需要先比較a[j]和a[k],如果: 1.相等,則next[j+1] = k++,求解完畢。同時j++,準備下一次迴圈; 2.不相等,則讓p[next[k]]再和p[j]比較:若 2.1 相等,則next[j+1]就是next[k]+1,求解完畢。同時j++,準備下一次迴圈。 2.2 不相等,則next[k]再往下迭代, 。。。 直到碰到next的值是-1時停止,表示匹配失敗。 */ if (k == -1 || p.charAt(j) == p.charAt(k)) { ++k; ++j; if(p.charAt[j] != p.charAt(k)){ next[j] = k; }else { next[j] = next[k]; } } else { k = next[k]; } } }