超詳細!終於搞明白KMP演算法

2021-10-10 18:32:20 字數 2744 閱讀 2105

小夥伴們好久不見,今天將開設「資料結構與演算法」專欄,一起梳理一遍硬核課程的重要知識點,那我們開始吧

字串匹配是計算機的基本任務之一,舉個栗子,有乙個字串「aaaaaaca",我想知道裡面是否包含另乙個字串「aaaac」,該怎麼辦?

這裡就會使用到串的模式匹配演算法,最常見的分別是傳統的brute-force(暴力)演算法kmp演算法

bf演算法設計思想

1、主串和模式串逐個字元進行比較

2、當出現字串不相同時,也就是失配時,主串的比較位置重置為起始位置的下乙個字元位置,模式串的比較位置重置為起始位置

3、匹配成功後返回主串中匹配串的起始位置,否則就返回錯誤**

bf演算法的設計缺陷及解決方案

在bf演算法中,每次失配都需要回溯指向上次比較起始字元的下乙個字元。通過觀察發現:在回溯的時候,已匹配似乎有一部分沒必要繼續比較了,這樣可以降低演算法的時間複雜度

kmp演算法的出現有效地解決了bf演算法的缺陷。kmp 演算法是 d.e.knuth、j,h,morris 和 v.r.pratt 三位神人共同提出的。

但是這種演算法相對於bf演算法不太容易理解,網上也有很多解釋,但配圖有點少,總感覺差點意思,下面我通過畫圖的方式詳細介紹kmp演算法的設計思想和工作原理

kmp演算法設計思想

在匹配過程**現字元比較不相等時,主串 s已比較的位置不回溯,模式串 t比較的位置進行移動

在匹配過程中有乙個難題需要解決:如何計算模式串 t失配時的移動位數?經過三位牛人的研究,設計出了部分匹配函式

部分匹配函式

部分匹配函式是kmp演算法中最難以理解的部分。首先需要理解字首字尾最大共有長度的概念。

· 字首:指除了最後乙個字元以外,乙個字串的全部頭部組合

· 字尾:指除了第乙個字元以外,乙個字串的全部尾部組合

· 最大共有長度(部分匹配值):指字首和字尾中的最大共有元素,沒有則為0。例如「abab」的字首為「a」、「ab」、「aba」,字尾為「b」、「ab」、「bab」,最大共有元素為「ab」,所以最大共有長度為 2

回顧一下kmp演算法的匹配過程:

紅線框出的部分恰好就是失配時已匹配部分,「aaaa」 的最大共有元素為 「aaa」,這一部分字元就是不需要再重複進行比較直接跳過的字元

在**實現過程中,j 移動後的位置 = 模式串 t 的起始位置下標 + 部分匹配值。通常起始下標為 0,因此 j 移動後位置 = 部分匹配值,即 j = next[j],next[j] 就是部分匹配函式,j 為失配時的位置

因此接下來就成了對部分匹配函式的是實現。將 「aaaac」 以首字元起始的所有子串的最大共有長度列舉出來,構成部分匹配表,它描述了失配時的下標 j 與部分匹配值的關係

部分匹配表則是通過模式串 t 的自匹配實現:

示例**(c語言哦):

/*kmp匹配演算法*/

int kmpcompare(hstring parent, hstring child, intpos)

else

} if (j == child.length)

return 0;

}/*部分匹配函式的實現*/

void get_next(hstring child, int * next)

else }}

void main()

關注即可提高學習效率!我是aime菌,下期再見!peace~

每天進步一點點,慢一點才能走得更快

終於搞明白了傳說中的setjmp,longjmp

int setjmp jmp buf jmpb 設定緩衝區來儲存堆疊的內容,將儲存的上下文存入程序的自身的資料空間 u區 並繼續在當前的上下文中執行,一旦碰到了longjmp,進城就從該程序 的u區,取出先前儲存的上下文,並恢復該程序的上下文為先前儲存的上下文。這時核心將使得程序從setjmp處執行...

擴充套件KMP超詳細理解

本文 希望原博主不要介意,介意的話我可以刪掉 前文已經介紹了經典的kmp演算法,本文繼續介紹kmp演算法的擴充套件,即擴充套件kmp演算法。問題定義 給定兩個字串s和t 長度分別為n和m 下標從0開始,定義extend i 等於s i s n 1 與t的最長相同字首的長度,求出所有的extend i...

KMP演算法詳細解讀

備註 2016.11.18,寫kmp演算法千萬不要忘了初始化next 0 1。ps 自從學會了寫偽 現在演算法水平大大的提公升了。kmp看了別人的部落格看懂了,然後自己寫一次性就ac了。kmp入門請參考這幾位大神 先總結思路 求next陣列的偽 是 getnext j 0 k 1 next 0 1 ...