資料結構 改進的KMP演算法

2021-09-22 20:08:38 字數 2096 閱讀 8189

ps:若不清楚kmp演算法的執行過程,可參考資料結構 —— kmp演算法)

如果我們要對下面的主串p和模式串p進行匹配

步驟一:i=3,j=3

模式串 「abab」 對應的 next 陣列為-1 0 0 1(0 0 1 2整體右移一位,初值賦為-1),當模式串 p 和主串 s 進行匹配時,發現b跟c失配,於是模式串 p 右移 j - next[ j ] = 3 - 1 =2位。

步驟二:i=3,j=1

右移2位後,b又跟c失配。事實上,因為在上一步的匹配中,已經得知 p[3] = b,與 s[3] = c失配,而右移兩位之後,讓p[ next[3] ] = p[1] = b 再跟 s[3] 匹配時,必然失配。問題出在哪呢?

問題在於,我們應該避免出現 p[j] = p[ next[j] ]的情況。當p[j] != s[i] 時,下次匹配必然是 p[ next [ j ] ] 跟 s[i] 匹配,如果 p[j] = p[ next[ j ] ],必然導致後一步匹配失敗(因為 p[j]已經跟 s[i]失配,然後你還用跟 p[j]等同的值 p[ next [ j ] ]去跟 s[i]匹配,很顯然,必然失配),所以不能允許 p[j] = p[ next [ j ]]。

由此可見,kmp 演算法仍存在不足之處

沒有利用到匹配失敗時的資訊(即p[j]),在使用 j=next[j] 進行回溯時進行了多餘的計算

因此,我們提出了改進的kmp演算法,對 next 陣列進行修正,得到 nextval 陣列

步驟一:i=3,j=3

因為 next[ 3 ]=1,故p[3] = p[ next[ 3 ] ] = p[1] = b ,next[3] 需要再次遞迴(因為當p[3] = p[ next[ 3 ] ]時,必然失配,所以要找到 next[ next [ 3 ] ]再進行匹配;如若繼續失配,則繼續往前尋找,直到找到不相等的p[next…]或到達臨界點 j=-1),即令 nextval[3] = next[ next [ 3 ] ] = next[1] = 0,p[ next[ 1 ] ] = p[0] = a,p[3] ≠ p[ next[ 1 ] ],故對 p[3] 和 p[ next[ 1 ] ] 進行匹配

步驟二:改進後變成了 i=3,j=0

此時,我們利用 nextval 解決了存在的問題

上述內容介紹了改進的 kmp 演算法的執行過程,那麼接下來我們將介紹如何求出 kmp 演算法中用到的 next 陣列

(前三步具體步驟省略,可參考資料結構 —— kmp演算法)

(1)尋找最長字首字尾

(2)得到最大長度表

(3)求出 next 陣列

(4)求出 nextval 陣列

將 nextval 的初值賦為 -1

當 p[ j ] = p[ next[ j ] ] 時,只需讓 nextval[ j ]賦值為 nextval [ next[ j ] ]。原因有兩點:

nextval 陣列 時從下標0開始逐步往後求得的,所以在求 nextval[j]時,nextval [ next[ j ] ]必定已經存在

nextval [ next[ j ] ]包含了前面的 nextval 的比較結果,因此無須再重複比較。

參考文章

資料結構 KMP演算法

求串的模式值next n 定義 1 next 0 1 意義 任何串的第乙個字元的模式值規定為 1。2 next j 1 意義 模式串t中下標為j的字元,如果與首字元相同,且 j的前面的 1 k個字元與開頭的 1 k個字元不等 或者相等但t k t j 1 k 如 t abcabcad 則next 6...

資料結構 KMP演算法

在我的理解,kmp演算法最核心的同時最難理解的是這個next 函式。但是,next 的值是挺好求的,難在哪呢?這個函式難在邏輯。理解起來很費勁,但真的很好用,並且這個函式的結果很好求。例如求模式串t ababaaa 的next j 的函式值 是這樣的,當j 0,next 0 1,對於任何子串,第乙個...

資料結構 KMP演算法

要完善乙個string字串類,那麼實現查詢子串的功能是必不可少的,實現子串查詢可以使用樸素演算法,每次匹配乙個字元後向右移動乙個位置,這樣執行下來效率是比較低的,所以就有了kmp演算法,它能夠準確的知道當前字元不匹配後字串應該向右移動多少位,由於剛接觸kmp演算法,所以很多還明白的不是很透徹,在此記...