模式匹配之KMP演算法

2021-07-29 22:13:59 字數 3249 閱讀 7397

前面講到過bf演算法,雖然簡單,但是效率比較低,kmp演算法對此做了很大改進,該演算法是由knuth,morris,pratt同時設計的,所以簡稱kmp演算法

為什麼說bf演算法效率低呢?比如s="34343434345",t="345",在位置3時,s中字元為『3』,t中為'5',不匹配,所以又重新從s中第2個位置,t中第1個位置開始匹配,匹配失敗,又從s中第3....

可以看到,在s中後面子串"345"之前的匹配中很多都是不必要的,這無疑大大增加執行的次數,這些回溯都是不必要的

假設在某次si和tj匹配失敗後,i不回溯,串t向右"移動"到某個位置,使得tk對準si繼續向右進行。

首先,匹配失敗因為si處的字元與tj處的字元不匹配,那麼tj前面的j-1個字元都是匹配的,所以:
"t1t2t3...t(j-1)"="s(i-j+1)s(i-j+2)...s(i-1)"

//1式

//t前面j-1個字元 //si前面j-1個字元

然後t向右"移動"到某個位置,使得tk對準si,那麼tk前的k-1個字元是匹配的,所以
"t1t2t3...t(k-1)"="s(i-k+1)s(i-k+2)...s(i-1)"

//2式

k肯定是小於j的,對吧,(之前是t串位置j處對準si,然後t向右"移動",使得tk對準si,所以k"t(j-k+1)t(j-k+2)...t(j-1)"="s(i-k+1)s(i-k+2)...s(i-1)"

//3式

由2式和3式可以得到:

"t1t2t3...t(k-1)"="t(j-k+1)t(j-k+2)...t(j-1)"

//4式

這說明了什麼呢?說明在某次si和tj匹配失敗後,如果串t中滿足前k-1個字元組成的串=串t中j-1位置前(包括j-1)k-1個字元組成的串,就可以將串t向右」移動」使得si對準tk,然後繼續進行比較

next陣列:

串中的每乙個tj都對應乙個k值,由上面的分析可知,k值僅僅取決於串t本身,與s無關,用next陣列來儲存tj對應的k值,next陣列具有以下性質:
1

:next[j]是乙個整數,且0

<=next[j]2

: 為了是t右移但不丟失任何匹配成功的可能,當存在多個滿足4式的k值時,

應選取最大的,使得t向右"移動"的距離最短,移動的字元為j-next[j]個

3:如果在tj前不存在滿足4式的子串,定義next[j]=1,即用t1和si比較

因此,next陣列定義如下:

當j=1時:

next[j]=0

當存在k滿足4式時:

next[j]=k(若有多個k,選最大的)

當不存在上面的k時:

next[j]=1

比如有子串t=「abcaababc」,其next陣列為:

next=

接下來就是kmp演算法的執行過程了,初始時i=j=1;

如果si==tj,則i和j分別+1,如果si!=tj,則i不變,j回溯到next[j],然後再比較,如果si==tj,則i,j分別加1,繼續匹配,以此類推,如果遇到next[j]==0,那麼i,j也要分別增加1

以下是主串」aabcbabcaabcaababc」,子串」abcaababc」的匹配過程

怎麼樣,確實省去了很多不必要的比較吧,接下來就是實現了,那麼如何求子串的next陣列呢?

由定義知:

next[1]=0;

設next[j]=k,即有:

"t1t2...t(k-1)"="t(j-k+1)...t(j-1)"

那麼next[j+1]等於什麼呢?分兩種情況:

1): 如果tk==tj,則:

"t1t2...t(k-1)tk"="t(j-k+1)...t(j-1)tj"

則next[j+1]=next[j]+1

2):如果tk!=tj,即:

"t1t2...t(k-1)tk"!="t(j-k+1)...t(j-1)tj"

此時可以將求next值的問題看成乙個模式匹配問題,整個串即是主串又是

子串,在當前匹配過程中,已有next[j]=k,則應將串向右移動,使得第next[k]個字元和"主串"的第j個字元比較,如果存在k',那麼

next[j+1]=next[k]+1

否則next[j+1]=1;

求解next陣列需要好好體會

getnext函式:

void getnext(string t,int (&next)[20])

else

j = next[j];}}

kmp演算法:

/*

模式匹配之kmp演算法

*/# include

# include

using

namespace

std;

void getnext(string t,int (&next)[20]);

int patternmatch_kmp(string s, string t,int (&next)[20]);

int main()

int patternmatch_kmp(string s, string t, int (&next)[20])//返回子串t在串s第一次出現的位置(從1開始),若t不是s的子串

//返回-1

模式匹配 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...