KMP演算法next陣列的一種理解思路

2022-04-12 02:02:33 字數 2873 閱讀 1012

這篇部落格提供一種理解kmp演算法中求解next陣列的思路,若是從頭開始學習kmp演算法,請移步這篇部落格閱,作者講解的十分詳細,我本人也是從他的部落格開始回顧kmp演算法,本篇部落格也是基於這篇部落格來寫的。

請閱讀到以下位置後,若是無法理解p[k] != p[j]這部分邏輯,希望可以嘗試用本篇部落格的思路來理解;若是理解了,這篇部落格也可以幫你以另外一種思路理解,所以本篇部落格作為這篇部落格的補充更為合適。

首先明確next陣列作用,設t為主串,p為模式串(即為關鍵字),next陣列作用為,當t[i] != p[j]後,模式串指標 j 應該回退到next[j]位置。

如果閱讀過我說的這篇部落格,就已經知道為什麼指標 j 不用回退到0而要回退到next[j],因為要充分利用已經匹配的字元和模式串的特徵來減少指標回退,以降低時間複雜度。

求解next陣列的**如下:

1

void getnext(int next, stringp)2

else

11 k =next[k];12}

13 }

其實我們可以將kmp演算法理解成兩次字串匹配的過程:

第一次發生在求next陣列過程中,就是模式串p的最長字首子串和最長字尾子串進行匹配的過程中,其中模式串是最長字首子串,主串是最長字尾子串,模式串和主串都在同乙個字串中。

補充:字首子串和字尾子串概念

字首子串:從字串頭開始的子串。例如字串:abcdef那麼它的字首子串為:a,ab,abc,abcd,最長的字首子串便為 abcde;

字尾子串: 從字串尾開始的子串。還是拿字串abcdef舉栗子它的字尾子串為:f,ef,def,最長的字尾子串便為 bcdef。

例如下圖:

假設它本身作為kmp演算法的模式串,但是在求next陣列中,又可以將它看為下面這樣:

也就是在"bcabcd"中匹配"abcabc"。

第二次當然是模式串p和主串t的匹配過程,比如下圖,也就是在下圖上面的主串中尋找下面的模式串。

在將kmp演算法理解成兩次匹配過程後,next[j]陣列含義就是這篇部落格提到的,模式串的字首子串集和字尾子串集的最長相同元素,也就是目前在 j 位置之前最長字首子串和最長字尾子串已經匹配字元的個數。如果肉眼去尋找這個結果是很簡單的。

例如求模式串"abacdababc"的next的陣列,此時的最長字首子串為"abacdabab"作為模式串,最長字尾子串為"bacdababc"作為主串(換一種說法,就是在最長字尾子串中尋找最長字首子串)。

當p[k] == p[j]時,如下圖:

已經匹配了"abc",j + 1位置的之前最長字首子串和最長字尾子串匹配個數就是 k + 1 = 2 + 1 = 3(k從0開始,所以需要加1),對應** 7~9行:

j++;

k++;

next[j] = k;

當p[k] != p[j]時,如下圖,作為模式串的最長字首子串的k指標應該回退,回退到什麼位置呢?

顯然根據已經求出的next資料,就可以知道k應該回退到什麼地方,k應該回退到next[k]位置,next[3] = 1,也就是k重新回到1位置,因為p[0 ~ next[k] - 1]已經和p[j - next[k] ~ j - 1]已經匹配,k指標只需要回退到next[k]位置再開始匹配即可,對應求next陣列的第11行**如下:

k = next[k];
最後處理兩種特殊情況:

當next陣列下標為0時,next[0] = -1, 放在第一次匹配過程中理解就是,當p[0] != p[j]時,k因該回退到-1,重新開始匹配過程;放在第二次匹配過程中理解就是,當p[0] != t[i]時,j 回退到-1,重新開始匹配過程。

當next陣列下標為1時,next[1] = 0,放在第一次匹配過程中理解就是,當p[1] != p[j]時,k因該回退到0,從頭開始開始匹配;放在第二次匹配過程中理解就是,當p[1] != t[i]時,j 回退到0,從頭開始開始匹配。

改進求next陣列方法:

上邊求next資料的方法有缺陷,再這裡設p為模式串,t為主串,當p[j] != t[i]時(無論是第一次還是第二次匹配過程都有,只不過第一次求next匹配過程的模式串和主串都在同乙個字串中)會存在模式串指標 j 不能一次性回退到位的情況,當出現如下圖情況時

按照第一種求next陣列方法j 應該回退到1,如下圖哦所示,但是當回退到1時,還是會出現p[j] != t[i]的情況,因為a後面跟的都是b,所以應當讓 j 直接回退到next[1] = 0,更為高效。

所以改變後**如下,改變在9~12行,在求next陣列匹配過程中,當p[k] == p[j]或者k == 1時,並且p[k + 1] == p[j + 1]時,next[j + 1] == next[k + 1]

1

void getnext2(int next, stringp)2

else

14 k =next[k];15}

16 }

KMP演算法 next陣列

通過上文完全可以對kmp演算法的原理有個清晰的了解,那麼下一步就是程式設計實現了,其中最重要的就是如何根據待匹配的模版字串求出對應每一位的最大相同前字尾的長度。我先給出我的 1 void makenext const char p,int next 214 next q k 15 16 現在我著重講...

KMP演算法 NEXT陣列

kmp和next陣列基本上是一起用的,有了next陣列,才有kmp演算法,講道理來說這兩個都是基於最大前字尾和,也就是說需要用到kmp的時候必須先把next陣列先求出來,next陣列就是由所匹配的word的每個子串的前字尾和最大匹配得到的,說實話next陣列的演算法給優化得已經很無解了,以至於至今我...

KMP演算法的next陣列

本文參考 google 資料結構 c語言 include include author silence time 2012 5 19 description kmp演算法的next using namespace std void next char t,int l,int next else 1 ...