next陣列的歷史
有關字串的模式匹配演算法中,比較容易寫出的是樸素的匹配演算法也就是一種暴力求解方式,但是由於其時間複雜度為子串長度和主串長度的乘積,例如strlen(substr) = n,strlen(mainstr) = m,則其時間複雜度為o(mn)。
為了能夠得到更有效的匹配演算法,d.e.knuth與v.r.pratt和j.h.morris同時發現,因此人們稱它為克努特--莫里斯--普拉特操作(簡稱kmp演算法)。kmp演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現乙個next()函式,函式本身包含了模式串的區域性匹配資訊。這也即是kmp演算法的設計思想。
next陣列的求解思路
求next陣列,next[j]表示,當模式串j位置與主串i位置處發生不匹配時,i指標不回溯,j指標回溯到next[j]的位置。
對於求next[j]有三種情況:
1、j = 0時,next[j] = -1;//即模式串的第乙個字元與主串i位置發生不匹配,應將i跳過當前位置,從下乙個位置和模式串的第乙個字元繼續比較。
2、假設已知next[j] = k,即substr[0,...,k-1] = substr[j-k,j-1]。當substr[k] = substr[j]時,也就是說模式串滿足substr[0,...,k] = substr[j-k,j],可以得知next[j+1] = k + 1 = next[j] + 1;
3、當substr[k] != substr[j]時,就需要從k位置之前去查詢與substr[j]匹配的位置,假設為j'。這樣問題又可以轉化為第二種情況,即next[j+1] = next[j'] + 1 = k' + 1。
三種求解next陣列的演算法
但是如何去求解next陣列呢?有關這個問題,我思考了很長時間,下面給出幾種演算法:
演算法一,嚴格根據next陣列的定義:
1void getnext(char substr,int
next)215
//情況三,不相等的話,要回溯j指標,substr[j'] = substr[i-1]的位置j'
16else
1726 t--;27}
28if (t < 0
)29 j = 0
;30 k =next[j];31}
3233
}34 }
演算法二,演算法的設計思想和演算法一大致相同
void getnext(constchar p, int
next)
if (p[q-1] == p[k])//
如果相等,那麼最大相同前字尾長度加1
if (k == -1
) k = 0
; next[q] =k;
}}
演算法三,更加優化的求解next陣列的演算法
void getnext(constchar substr, int
next)
//情況三,不同則j指標回溯
else
j =next[j];
}}
現在來進行總結一下,對於演算法一和演算法二來說,它們的時間複雜度是一樣的,但是相對於演算法三來說,雖然不如演算法三高效,但是比較容易理解!
ps:如果有誤的地方,請指出,共同進步!
KMP演算法Next陣列求解
相信對於kmp演算法本身大家都理解,最難理解的就是這個next陣列的求解了。這是 p 為模式串,下標從 0 開始 void getnext string p,int next else j next j 根據我的理解,i 和 j 可以看成是兩個指標,用來跟蹤當前匹配的位置。可以發現 i 是會不斷的往...
KMP演算法 next陣列的求解
void getnext vector int next,string s if s i s j next i j 為什麼j按照上述的更新方法,是s 0 i 這個字串中字首和字尾相等的最大字串的長度 j的更新方式 如果s i s j j一直回退 j next j 1 直到回退到s j s i 如果s...
KMP演算法 快速求解next陣列
在kmp演算法中,最關鍵的就是求解next陣列了。那麼如何快速求解next陣列呢?已知模式串 ab cdabdd a 其next陣列 00 0 0 12 0 0 1 那麼是如何求證出來的呢?首先字串從左至右遍歷。第乙個字元a的next陣列對應元素為0,第乙個字元a和第2個字元b比,不相等。b 0 表...