KMP模式匹配演算法

2021-10-02 12:13:19 字數 4415 閱讀 5229

符號說明i

主串當前位置的下標(不回溯)

j模式串t當前位置的下標

目的:原本的匹配時 i 和 j 不停的回溯,kmp模式匹配讓 i 不用回溯。

j 值的變化與主串無關,取決於模式串t的結構中是否有重複(即當前字元之前的串的前字尾的相似度)。

我們把模式串t各個位置的 j 值的變化定義為乙個陣列 next,那麼next的長度就是模式串t的長度。由此得出以下的函式定義:

n ex

t[j]

=,

當此集合不為空時1,

其他情況

next[j]= \begin 0,& \text\\ max\,1

,​當j=1

時當此集合不為空時

其他情況

​具體要怎麼推導出來乙個串的next陣列值呢,來看一些例子:

1、t=「abcdex」

j123456

模式串t

abcdex

next[j]

011111

當 j=1 時,next[1]=0;

當 j=2 時,j 由1到 j-1 就只有字串 「a」,屬於其他情況,next[2]=1;

當 j=3 時,j 由1到 j-1 就只有字串 「ab」,顯然「a」與「b」不相等,屬於其他情況,next[3]=1;

以後同理可得,得出最終t串的next[j] 為011111

2、t=「abcabx」

j123456

模式串t

abcabx

next[j]

011123

當 j=1 時,next[1]=0;

當 j=2 時,同上例說明,next[2]=1;

當 j=3 時,同上next[3]=1;

當 j=4 時,同上next[4]=1;

當 j=5 時,此時j 由1到 j-1 字串是 「abca」,字首字元的「a」(黃色強調)與字尾字元的「a」相等,因此可推算出k值為2(由』p[1]…p[k-1]』=『p[j-k+1]…p[j-1]』,得到p[1]=p[4])因此next[5]=2;

當 j=6 時,j 由1到 j-1 字串是 「abcab」,字首字元的「ab」與字尾字元的「ab」相等,因此可推算出k值為3(由』p[1]…p[k-1]』=『p[j-k+1]…p[j-1]』,得到p[1]p[2]=p[4]p[5])因此next[6]=3;

我們可以根據經驗得到如果前字尾乙個字元相等,k的值是2,兩個字元k的值是3。n個相等的k值就是n+1。

3、t=「ababaaaba」

j123456789

模式串t

ababaaaba

next[j]

011234223

當 j=1 時,next[1]=0;

當 j=2 時,同上next[2]=1;

當 j=3 時,同上next[3]=1;

當 j=4 時,j 由1到 j-1 的字串是 「aba」,字首字元的「a」(黃色強調)與字尾字元的「a」相等,next[4]=2;

當 j=5 時,j 由1到 j-1 字串是 「abab」,字首字元的「ab」(黃色強調)與字尾字元的「ab」相等,因此next[5]=3;

當 j=6 時,j 由1到 j-1 字串是 「ababa」,字首字元的「aba」與後面的「aba」相等,因此next[6]=4;

當 j=7 時,j 由1到 j-1 字串是 「ababaa」,由於字首字元的「ab」與後面的「aa」不相等,只有「a」相等,因此next[7]=2;

當 j=8 時,j 由1到 j-1 字串是 「ababaaa」,只有「a」相等,因此next[8]=2;

當 j=9 時,j 由1到 j-1 字串是 「ababaaab」,字首字元的「ab」(黃色強調)與字尾字元的「ab」相等,因此next[9]=3;

4、 t=「aaaaaaaab」

j123456789

模式串t

aaaaaaaab

next[j]

012345678

當 j=1 時,next[1]=0;

當 j=2 時,同上next[2]=1;

當 j=3 時,j 由1到 j-1 的字串是 「aa」,字首字元的「a」(黃色強調)與字尾字元的「a」相等,next[3]=2;

當 j=4 時,j 由1到 j-1 的字串是 「aaa」,字首字元的「aa」(黃色強調)與字尾字元的「aa」相等,next[4]=3;

…當 j=9 時,j 由1到 j-1 字串是 「aaaaaaaa」,字首字元的「aaaaaaa」與後面的「aaaaaaa」相等,因此next[6]=8;

/*通過計算返回子串t的next陣列*/

void

get_next

(string t, vector<

int>

& next)

//next長度要比t的長度大1,next從0開始,t從1開始

else

i = next[i]

;/*若字元不相同,則i回溯到前面重新比較*/}}

/*返回匹配串t在主串s中第pos個字元之後的位置。若不存在,則函式返回值為0*/

/*t非空,1<=pos<=s.length()*/

intindex_kmp

(string s, string t,

int pos)

else

/*回溯*/}if

(j >= t_len)

return i - t_len;

else

return-1

;}

前者依然存在缺陷:當主串s=「aaaabcde」,匹配串t=「aaaaax」,其next陣列值分別012345,在開始時,當 i=5、j=5 時,我們發現 「b」 和 「a」 不相等,因此j=next[5]=4,此時 「b」 與第四位置的 「a」 依然不等, j=next[4]=3,後面 j 依次是 3 2 ,直到 j=next[1]=0 時,根據演算法,i++、j++,得到 i=6、j=1。

我們發現,j從等於4直到等於0這些步驟都是多餘的判斷。由於t串的第2、3、4、5位置的字元與首位的 「a」 相等,那麼可以用首位next[1]的值去替代與他相等的後續字元 next[j] 的值,因此我們對next函式進行改良。

void

get_nextval

(string t, vector<

int>

& nextval)

else

i = nextval[i];}

}

1、t=「ababaaaba」

j123456789

模式串t

ababaaaba

next[j]

011234223

nextval[j]

010104210

當 j=1 時,next[1]=0;

當 j=2 時,因為第二位字元 「b」 的next值為1,而第一位就是 「a」 ,它們不相等,所以nextval[2]=next[2]=1,維持原值;

當 j=3 時,因為第三位字元 「a」 的next值為1,所以與第一位的 「a」 比較得知它們相等,,所以nextval[3]=nextval[1]=0;

當 j=4 時,第四位字元 「b」 的next值為2,所以與第二位的 「b」 比較得知它們相等,,所以nextval[4]=nextval[2]=0;

當 j=5 時,next值為3,第五個字元 「a」 與第三個字元 "a"相等,所以nextval[5]=nextval[3]=0;

當 j=6 時,next值為4,第六個字元 「a」 與第四個字元 "b"不相等,所以nextval[6]=4;

當 j=7 時,next值為4,第六個字元 「a」 與第四個字元 "b"不相等,所以nextval[6]=4;

當 j=8 時,next值為2,第八個字元 「b」 與第二個字元 "b"相等,所以nextval[8]=nextval[2]=1;

當 j=9 時,next值為3,第九個字元 「a」 與第三個字元 "a"相等,所以nextval[9]=nextval[3]=1;

4、 t=「aaaaaaaab」

j123456789

模式串t

aaaaaaaab

next[j]

012345678

nextval[j]

000000008

當 j=1 時,nextval[1]=0;

當 j=2 時,next值為1,第二個字元與第乙個字元相等,所以nextval[2]=nextval[1]=0;

同樣的道理,後面都為0…

當 j=9 時,next值為8,第九個字元 「b」 與第八個字元 「a」 不相等,所以nextval[9]=8;

總結:改進的kmp演算法,它是在計算出next值的同時,如果 a 位字元與它的 next值指向的b位字元相等,則該 a 位的nextval就指向nextval值,如果不等,則該 a 位的nextval值就是它自己 a 位的next值。

模式匹配 KMP演算法

字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...

模式匹配KMP演算法

前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...

KMP模式匹配演算法

首先,這是由knuth morris和prattle三人設計的線性時間字串匹配演算法。這裡就不仔細的講解,網上有更好的講解,在這推薦幾個自己當時學習的kmp所看到的較好理解的 這裡附上自己所學的 includeusing namespace std s 是主串 p 是模式串 int next 100...