1. 程式人生 > >KMP演算法的理解

KMP演算法的理解

什麼是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];  
        }  
    }  
}