對KMP演算法的next陣列的理解

2021-10-09 17:28:14 字數 2667 閱讀 3345

最近正在看《大話資料結構》,在看到kmp演算法的時候怎麼進行字串匹配的基本上可以理解,但是在看原始碼求解next陣列的時候,我蒙了,一頭霧水,和我想象的完全不一樣,真的好簡潔,簡潔到我都不知道為什麼會這樣寫,我試圖**所以然,然後研究了將近三天時間,因此在這僅僅說明我對next陣列的理解。如果理解錯誤的還請大佬指正,也歡迎交流,共同分享一下各自的想法。

kmp演算法主要是用於解決字串匹配的問題,演算法的前世今生我就不說了,別的部落格都有涉及到,而且不是今天文章的重點。kmp演算法的基本思想就是「僅僅移動模式串,比較指標不回溯」,這是因為在樸素的字串匹配演算法中需要遍歷主串和模式串,假設主串的長度為n,模式串的長度為m,因此樸素模式匹配演算法的時間複雜度是o((n-m+1)*m),比較慢。在逐個匹配的過程中發現有很多不必要的額外比較操作,這些操作完全是可以通過改進演算法進行規避的,因此kmp演算法就這樣問世了。它借助next陣列,在不回溯主串比較指標的前提下,快速調整模式串從哪個元素的索引開始進行比較,因此從這兩個方面上減少迴圈的次數,提高演算法的速度。

首先,簡單介紹kmp演算法的處理流程,然後歸納出三種情況並通過**實現。

假設模式串為「abcabx」,下面陣列的第一行表示各個字元的索引,第二行表示模式串中有六個字元。

0

1

2

3

4

5a

b c

a b

x 在了解kmp演算法之前,還需要熟悉幾個概念。第乙個概念就是模式串中對稱的「字首」和「字尾」,舉個例子,比如索引4也就是字元「b」與主串對應元素不相同,但是它之前的「abca」字串中存在對稱的「字首」和「字尾」,就比如這樣

我們就可以移動模式串的「字首」到與之對稱的「字尾」位置,就比如右圖這樣,這樣就避免了多餘的比較操作,否則就需要前移主串的比較指標並對模式串進行主串「a」與模式串「a」再一次進行比較的冗餘操作。

因此,next陣列中儲存的就是當該字元與主串字元不匹配時,該字元應該回到哪個索引位置上再與主串進行比較。從上面的案例我們可以發現,當我們索引到字元b的時候,我們只需要觀察字元b之前的「abca」字串中是否存在對稱前字尾即可,我們暫且用k和i表示前字尾尾索引,上述案例中,當求字元b的next數值的時候,因為「字尾」a和「字首」a構成對稱,因此,字元b的next數值就是「字首」a的下乙個索引位置,表示「字首」和「字尾」進行對齊,主串和「字首」a的下乙個字元進行比較,如下圖所示。

從上面的過程中,我們可以歸納以下幾點:首先,「abcabx」一共有6個字元,字尾尾索引的範圍就是[0, 4];k表示上乙個字首尾索引的下乙個字元的索引;next陣列中存放著每個字元的回溯索引位置,而next陣列中的值就與k值有著密不可分的關係。下面就來說明一下next陣列如何確定。

下面歸納一下在比較的過程中會出現的三種情況:

(1)模式串當前字元之前的所有字元不存在對稱的前字尾。這時候就需要移動主串比較指標,並設定該字元的next陣列的數值為0,表示要回到模式串的首個位置處與主串進行比較。

(2)模式串當前字元之前的所有字元存在對稱的前字尾。這時候就需要設定當前字元的next陣列為字首尾索引的下乙個索引。

上面的兩種情況,我們可以使用k和i通過比較來表示。

(1)如果k = -1或者t[k] == t[i],前者表明當前字元的next陣列為k+1,並移動字首尾指標的位置,我們可以用++k來代替上述兩個步驟,然後就需要進行模式串中下乙個字元next陣列的計算,需要++i;t[k] == t[i]表明存在對稱的前字尾,因此需要設定當前字元next的陣列值為k+1,並移動i和k;因此上述兩種情況都可以用next[++i] = ++k一行**來表示。

(2)如果不存在對稱的前字尾,我們就需要找第k個字元需要回溯的索引位置。為什麼要回溯k的值,這是因為如果t[i] != t[k],那麼就無法在上乙個對稱的前字尾的基礎上進一步擴大對稱前字尾的範圍,因此只能在往前尋找能構成對稱的前字尾。因為t[k-1]與t[i-1]相等,也就是說t[next[k]-1]和t[i-1]相等,這已經構成了乙個對稱前字尾,只需要判斷t[next[k]]與t[i]是否相等,如果相等的話,就構成了乙個最大的對稱前字尾,否則再往前找。

因此上面的兩種情況就可以用**來表示:

void get_next(string t, int *next) 

}

因此,整個kmp演算法**就是這樣的:

int index_kmp() ;

get_next(t, next);

int i = 0;

int j = 0;

while (i < 15 && j < 6)

else

// 僅僅移動模式串,比較指標不回溯

j = next[j];

} if (j >= 6)

return i - 6;

else

return -1;

}

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 ...

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陣列的演算法給優化得已經很無解了,以至於至今我...