KMP演算法(快速模式匹配演算法)c語言

2021-10-01 02:24:36 字數 4084 閱讀 6486

傳統的bf演算法容易理解且實現,但是查詢效率不高,kmp本身不複雜,關鍵在於next陣列的構建,但網上絕大部分的文章把它講混亂了。下面,我們闡述kmp的流程 步驟、next 陣列的簡單求解 遞推原理 **求解,希望更多的人不再被kmp折磨或糾纏,不再被一些混亂的文章所混亂。

kmp演算法的核心,是乙個被稱為部分匹配表(partial match table)的陣列。我覺得理解kmp的最大障礙就是很多人在看了很多關於kmp的文章之後,仍然搞不懂pmt中的值代表了什麼意思。這裡我們拋開所有的枝枝蔓蔓,先來解釋一下這個資料到底是什麼。對於字串「abababca」,它的pmt如下表所示:

就像例子中所示的,如果待匹配的模式字串有8個字元,那麼pmt就會有8個值。我先解釋一下字串的字首和字尾。如果字串a和b,存在a=bs,其中s是任意的非空字串,那就稱b為a的字首。例如,」harry」的字首包括,我們把所有字首組成的集合,稱為字串的字首集合。同樣可以定義字尾a=sb, 其中s是任意的非空字串,那就稱b為a的字尾,例如,」potter」的字尾包括,然後把所有字尾組成的集合,稱為字串的字尾集合。要注意的是,字串本身並不是自己的字尾。有了這個定義,就可以說明pmt中的值的意義了。pmt中的值是字串的字首集合與字尾集合的交集中最長元素的長度。例如,對於」aba」,它的字首集合為,字尾 集合為。兩個集合的交集為,那麼長度最長的元素就是字串」a」了,長 度為1,所以對於」aba」而言,它在pmt表中對應的值就是1。再比如,對於字串」ababa」,它的字首集合為,它的字尾集合為, 兩個集合的交集為,其中最長的元素為」aba」,長度為3。

在模式串和主串匹配時,各有乙個指標指向當前進行匹配的字元(主串中是指標 i ,模式串中是指標 j ),在保證 i 指標不回溯的前提下,如果想實現功能,就只能讓 j 指標回溯。

j 指標回溯的距離,就相當於模式串向右移動的距離。 j 指標回溯的越多,說明模式串向右移動的距離越長。

計算模式串向右移動的距離,就可以轉化成:當某字元匹配失敗後, j 指標回溯的位置。

對於乙個給定的模式串,其中每個字元都有可能會遇到匹配失敗,這時對應的 j 指標都需要回溯,具體回溯的位置其實還是由模式串本身來決定的,和主串沒有關係。

模式串中的每個字元所對應 j 指標回溯的位置,可以通過演算法得出,得到的結果相應地儲存在乙個陣列中(預設陣列名為 next )。

計算方法是:對於模式串中的某一字元來說,提取它前面的字串,分別從字串的兩端檢視連續相同的字串的個數,在其基礎上 +1 ,結果就是該字元對應的值。

每個模式串的第乙個字元對應的值為 0 ,第二個字元對應的值為 1 。

例如:求模式串 「abcabac」 的 next 。前兩個字元對應的 0 和 1 是固定的。

對於字元 『c』 來說,提取字串 「ab」 ,『a』 和 『b』 不相等,相同的字串的個數為 0 ,0 + 1 = 1 ,所以 『c』 對應的 next 值為 1 ;

第四個字元 『a』 ,提取 「abc」 ,從首先 『a』 和 『c』 就不相等,相同的個數為 0 ,0 + 1 = 1 ,所以,『a』 對應的 next 值為 1 ;

第五個字元 『b』 ,提取 「abca」 ,第乙個 『a』 和最後乙個 『a』 相同,相同個數為 1 ,1 + 1 = 2 ,所以,『b』 對應的 next 值為 2 ;

第六個字元 『a』 ,提取 「abcab」 ,前兩個字元 「ab」 和最後兩個 「ab」 相同,相同個數為 2 ,2 + 1 = 3 ,所以,『a』 對應的 next 值為 3 ;

最後乙個字元 『c』 ,提取 「abcaba」 ,第乙個字元 『a』 和最後乙個 『a』 相同,相同個數為 1 ,1 + 1 = 2 ,所以 『c』 對應的 next 值為 2 ;

所以,字串 「abcabac」 對應的 next 陣列中的值為(0,1,1,1,2,3,2)。

上邊求值過程中,每次都需要判斷字串頭部和尾部相同字元的個數,而在編寫演算法實現時,對於某個字元來說,可以借用前乙個字元的判斷結果,計算當前字元對應的 next 值。

具體的演算法如下:

模式串t為(下標從1開始):「abcabac」

next陣列(下標從1開始): 01

第三個字元 『c』 :由於前乙個字元 『b』 的 next 值為 1 ,取 t[1] = 『a』 和 『b』 相比較,不相等,繼續;由於 next[1] = 0,結束。 『c』 對應的 next 值為1;(只要迴圈到 next[1] = 0 ,該字元的 next 值都為 1 )

模式串t為: 「abcabac」

next陣列(下標從1開始):011

第四個字元 』a『 :由於前乙個字元 『c』 的 next 值為 1 ,取 t[1] = 『a』 和 『c』 相比較,不相等,繼續;由於 next[1] = 0 ,結束。『a』 對應的 next 值為 1 ;

模式串t為: 「abcabac」

next陣列(下標從1開始):0111

第五個字元 』b』 :由於前乙個字元 『a』 的 next 值為 1 ,取 t[1] = 『a』 和 『a』 相比較,相等,結束。 『b』 對應的 next 值為:1(前乙個字元 『a』 的 next 值) + 1 = 2 ;

模式串t為: 「abcabac」

next陣列(下標從1開始):01112

第六個字元 『a』 :由於前乙個字元 『b』 的 next 值為 2,取 t[2] = 『b』 和 『b』 相比較,相等,所以結束。『a』 對應的 next 值為:2 (前乙個字元 『b』 的 next 值) + 1 = 3 ;

模式串t為: 「abcabac」

next陣列(下標從1開始):011123

第七個字元 『c』 :由於前乙個字元 『a』 的 next 值為 3 ,取 t[3] = 『c』 和 『a』 相比較,不相等,繼續;由於 next[3] = 1 ,所以取 t[1] = 『a』 和 『a』 比較,相等,結束。『a』 對應的 next 值為:1 ( next[3] 的值) + 1 = 2 ;

模式串t為: 「abcabac」

next陣列(下標從1開始):0111232

演算法實現:

void next(char *t,int *next)

else

j=next[j];

} if(j>strlen(t))

return i-(int)strlen(t);

return -1;

}

#include#includevoid next(char *t,int *next)

int main()

注意:kmp 演算法的關鍵在於 next 陣列的確定,其實對於上邊的kmp演算法中的next陣列,不是最精簡的,還可以簡化。

例如:模式串t:a b c a c

next :0 1 1 1 2

在模式串「abcac」中,有兩個字元 『a』,我們假設第乙個為 a1,第二個為 a2。在程式匹配過程中,如果 j 指標指向 a2 時匹配失敗,那麼此時,主串中的 i 指標不動,j 指標指向 a1 ,很明顯,由於 a1==a2,而 a2!=s[i],所以 a1 也肯定不等於 s[i]。

為了避免不必要的判斷,需要對 next 陣列進行精簡,對於「abcac」這個模式串來說,由於 t[4] == t[next[4]] ,所以,可以將next陣列改為:

模式串t:a b c a c

next :0 1 1 0 2

這樣簡化,如果匹配過程中由於 a2 匹配失敗,那麼也不用再判斷 a1 是否匹配,因為肯定不可能,所以直接繞過 a1,進行下一步。

實現**:

void next(char *t, int *next)

{  int i = 1;

next[1] = 0;

int j = 0;

while (i使用精簡過後的 next 陣列在解決例如模式串為「aaaaaaab」這類的問題上,會減少很多不必要的判斷次數,提高了kmp演算法的效率。

例如:精簡前為 next1,精簡後為 next2:

模式串:a a a a a a a b

next1:0 1 2 3 4 5 6 7

next2:0 0 0 0 0 0 0 7

至此,kmp演算法就全部介紹完了。

快速模式匹配演算法(KMP)

恐怕現在用過電腦的人,一定都知道大部分帶文字編輯功能的軟體都有乙個快捷鍵ctrl f 吧 比如word 這個功能主要來完成 查詢 替換 和 全部替換 功能的,其實這就是典型的模式匹配的應用,即在文字檔案中查詢串。1.模式匹配 模式匹配的模型大概是這樣的 給定兩個字串變數s和p,其中s成為目標串,其中...

KMP演算法 快速模式匹配演算法 詳解以及C語言實現

串的普通模式匹配演算法 bf演算法 大體思路是 模式串從主串的第乙個字元開始匹配,每匹配失敗,主串中記錄匹配進度的指標 i 都要進行 i j 1 的回退操作 這個過程稱為 指標回溯 同時模式串向後移動乙個字元的位置。一次次的迴圈,直到匹配成功或者程式結束。kmp演算法相比於bf演算法,優勢在於 故,...

模式匹配演算法 KMP演算法

一.基本概念 真字首指的是除了本身以外字串全部頭部的組合,真字尾指的是除了本身以外字串全部尾部的組合。二.簡單的模式匹配演算法 按照正常的思維,字串可以進行暴力匹配,如下。int index bf string s,string p else if j p len else return 1 暴力匹...