KMP演算法 感悟

2021-05-22 06:27:54 字數 4270 閱讀 3750

先說下我的教材:資料結構--c語言描述(耿國華 主編)

第四章 串

其中有個模式匹配演算法,一般的演算法看懂之後,在網上找了kmp演算法看,看了老長時間才看明白,真高興,和大家分享下

#define maxlen 40

#include

#include

typedef struct

sstring;

int strindex(sstring s,sstring t,int pos)

{int i,j,start;

if(t.len==0)

return 0;

start=pos;

i=start;

j=0;

while(i下面介紹傳說中的kmp演算法:

kmp演算法是一種改進的字串匹配演算法,由d.e.knuth與v.r.pratt和j.h.morris同時發現,因此稱之為kmp演算法。此演算法可以在o(n+m) 的時間數量級上完成串的模式匹配操作,其基本思想是:每當匹配過程中出現字串比較不等時,不需回溯指標,而是利用已經得到的「部分匹配」結果將模式向右 「滑動」盡可能遠的一段距離,繼續進行比較。

在s=」abcabcabdabba」中查詢t=」abcabd」,如果使用kmp匹配算 法,當第一次搜尋到s[5] 和t[5]不等後,s下標不是回溯到1,t下標也不是回溯到開始,而是根據t中t[5]==』d』的模式函式值(next[5]=2,為什麼?後面講), 直接比較s[5] 和t[2]是否相等,因為相等,s和t的下標同時增加;因為又相等,s和t的下標又同時增加。。。最終在s中找到了t。如圖:

kmp匹配演算法和簡單匹配演算法效率比較,乙個極端的例子是:

在s=「aaaaaa…aab「(100個a)中查詢t=」aaaaaaaaab」, 簡單匹配演算法每次都是比較到t的結尾,發現字元不同,然後t的下標回溯到開始,s的下標也要回溯相同長度後增1,繼續比較。如果使用kmp匹配演算法,就不必回溯.

對於一般文稿中串的匹配,簡單匹配演算法的時間複雜度可降為o (m+n),因此在多數的實際應用場合下被應用。

kmp演算法的核心思想是利用已經得到的部分匹配資訊來進行後面的匹配過程。看前面的例子。為 什麼t[5]==』d』的模式函式值等於2(next[5]=2),其實這個2表示t[5]==』d』的前面有2個字元和開始的兩個字元相同,且 t[5]==』d』不等於開始的兩個字元之後的第三個字元(t[2]=』c』).如圖:

也就是說,如果開始的兩個字元之後的第三個字元也為』d』,那麼,儘管t[5]==』d』的 前面有2個字元和開始的兩個字元相同,t[5]==』d』的模式函式值也不為2,而是為0。

前面我說:在s=」abcabcabdabba」中查詢t=」abcabd」,如果使用kmp匹配演算法,當第一次搜尋到s[5] 和t[5]不等後,s下標不是回溯到1,t下標也不是回溯到開始,而是根據t中t[5]==』d』的模式函式值,直接比較s[5] 和t[2]是否相等。。。為什麼可以這樣?

剛才我又說:「(next[5]=2),其實這個2表示t[5]==』d』的前面有2個字元 和開始的兩個字元相同」。請看圖  :因為,s[4] ==t[4],s[3] ==t[3],根據next[5]=2,有t[3]==t[0],t[4] ==t[1],所以s[3]==t[0],s[4] ==t[1](兩對相當於間接比較過了),因此,接下來比較s[5] 和t[2]是否相等。。。

有人可能會問:s[3]和t[0],s[4] 和t[1]是根據next[5]=2間接比較相等,那s[1]和t[0],s[2] 和t[0]之間又是怎麼跳過,可以不比較呢?因為s[0]=t[0],s[1]=t[1],s[2]=t[2],而t[0]  !=  t[1], t[1]  !=  t[2],==>  s[0]  != s[1],s[1] != s[2],所以s[1]  != t[0],s[2] != t[0].  還是從理論上間接比較了。

有人疑問又來了,你分析的是不是特殊輕況啊。

假設s不變,在s中搜尋t=「abaabd」呢?答:這種情況,當比較到s[2]和t[2] 時,發現不等,就去看next[2]的值,next[2]=-1,意思是s[2]已經和t[0] 間接比較過了,不相等,接下來去比較s[3]和t[0]吧。

假設s不變,在s中搜尋t=「abbabd」呢?答:這種情況當比較到s[2]和t[2] 時,發現不等,就去看next[2]的值,next[2]=0,意思是s[2]已經和t[2]比較過了,不相等,接下來去比較s[2]和t[0]吧。

假設s=」abaabcabdabba」在s中搜尋t=「abaabd」呢?答:這種情況當 比較到s[5]和t[5]時,發現不等,就去看next[5]的值,next[5]=2,意思是前面的比較過了,其中,s[5]的前面有兩個字元和t的開 始兩個相等,接下來去比較s[5]和t[2]吧。

總之,有了串的next值,一切搞定。那麼,怎麼求串的模式函式值next[n]呢?(本文 中next值、模式函式值、模式值是乙個意思。)

怎麼求串的模式值next[n]

定義:(1)next[0]= -1  意義:任何串的第乙個字元的模式值規定為-1。

(2)next[j]= -1   意義:模式串t中下標為j的字元,如果與首字元相同,且j的前面的1—k個字元與開頭的1—k個字元不等(或者相等但t[k]==t[j])(1≤k(3)next[j]=k    意義:模式串t中下標為j的字元,如果j的前面k個字元與開頭的k個字元相等,且t[j] != t[k] (0≤k舉例:

01)求t=「abcac」的模式函式的值。

next[0]= -1  根據(1)

next[1]=0   根據 (4)   因(3)有1<=knext[2]=0   根據 (4)   因(3)有1<=knext[3]= -1  根據 (2)

next[4]=1   根據 (3)  t[0]=t[3] 且 t[1]=t[4]

即    下標0

1234

tabc

acnext-10

0-11若t=「abcab」將是這樣:下標0

1234

tabc

abnext-10

0-10為什麼t[0]==t[3],還會有next[4]=0呢, 因為t[1]==t[4], 根據 (3)」 且t[j] != t[k]」被劃入(4)。

02)來個複雜點的,求t=」ababcaabc」 的模式函式的值。

next[0]= -1 根據(1)

next[1]=0   根據(4) next[2]=-1   根據 (2)

next[3]=0   根據 (3) 雖t[0]=t[2] 但t[1]=t[3] 被劃入(4)

next[4]=2   根據 (3) t[0]t[1]=t[2]t[3] 且t[2] !=t[4]

next[5]=-1  根據 (2) 

next[6]=1   根據 (3) t[0]=t[5] 且t[1]!=t[6]

next[7]=0   根據 (3) 雖t[0]=t[6] 但t[1]=t[7] 被劃入(4)

next[8]=2   根據 (3) t[0]t[1]=t[6]t[7] 且t[2] !=t[8]即下標

0123

4567

8tab

abca

abcnext-10

-102-1

102只要理解了next[3]=0,而不是=1,next[6]=1,而不是= -1,next[8]=2,而不是= 0,其他的好象都容易理解。

03)   來個特殊的,求 t=」abcabcad」 的模式函式的值。下標0

1234

567t

abca

bcad

next-10

0-100

-14next[5]= 0  根據 (3) 雖t[0]t[1]=t[3]t[4],但t[2]==t[5]

next[6]= -1  根據 (2) 雖前面有abc=abc,但t[3]==t[6]

next[7]=4   根據 (3) 前面有abca=abca,且 t[4]!=t[7]

若t[4]==t[7],即t=」 adcadcad」,那麼將是這樣:next[7]=0, 而不是= 4,因為t[4]==t[7].下標0

1234

567t

adca

dcad

next-10

0-100

-10如果你覺得有點懂了,那麼

練習:求t=」aaaaaaaaaab」 的模式函式值,並用後面的求模式函式值函式驗證。

意義:next 函式值究竟是什麼含義,前面說過一些,這裡總結。

1.  next[n]=  -1 表示s[m]和t[0]間接比較過了,不相等,下一次比較 s[m+1] 和t[0]

2.  next[n]=0 表示比較過程中產生了不相等,下一次比較 s[m] 和t[0]。

3.  next[n]= k >0 但k

我就是看這個看懂的,也引用了很多部分。

KMP演算法感悟

學了幾天kmp演算法。開始覺得有點難懂,但是堅持下來了,最終搞明白了,還是蠻開心的。所以寫點kmp演算法的感悟 1 next陣列只和模式串本身有關和文字串是無關的,因為next表示的是當匹配失敗後模式串要回溯到哪個位置。2 next陣列儲存的資料是用來當模式串與主串不匹配的時候要模式串回退到第幾個字...

KMP演算法個人感悟

既然來到了這,那也一定是被kmp困惑了一陣的小夥伴。雖然這篇文章也不一定讓你能看懂,但是這算是我自己個人對於kmp的最直接的理解,也許不好,也許有誤,望大佬指出。對於串的模式匹配的演算法很多,當然最簡單就是暴力破解法 也即是bf演算法 由此我們從這開始引入 bf演算法原理就是將主串和模式串依次進行比...

演算法 KMP演算法

kmp演算法主要解決的問題就是在字串 主串 中的模式 pattern 定位問題。記主串為t,模式串為p,則kmp演算法就是返回p在t 現的具體位置,如果沒有出現則返回 1。如果 i 指標指向的字元和 j 指標指向的字元不一致,那麼把 i 右移1位,j 從0位開始,從新開始匹配 如果 i 指標指向的字...