kmp演算法的基本總結

2021-07-04 23:37:43 字數 2890 閱讀 5092

字串的快速匹配kmp演算法
1,樸素的模式匹配演算法

目標串      t            t0  t1  t2  t3   t4  t5   t6  t7   t8  t9……

模式串      pat         p0 p1 p2 p3  p4 p5  p6 p7  p8 p9……

如果t0=p0,t1=p1,t2=p2   tm-1=pm-1,則字串匹配成功,否則將pat串後移一位

形成目標串      t            t0  t1  t2  t3   t4  t5   t6  t7   t8  t9……

模式串      pat              p0 p1 p2 p3  p4 p5  p6 p7  p8 p9……

再次進行匹配判斷,失敗再後移一位,如果tn-1和pm-1不相等,則匹配結束,返回不存在目標串中不含有字串

這種匹配演算法是帶回溯的演算法,一旦比較不相等,就將模式串pat後移一位,從p0開始判斷,設目標串的長度為n,匹配串的長度為m,第一趟失敗比較m次,第二趟失敗又比較m次,依次下去,最壞的情況是比較n-m+1次,在多數的情況下m是遠小於n的,所以可以認為演算法的時間複雜度是o(m*n)。由此我們引入一種不回溯的匹配演算法,提高匹配的效率。

2改進的演算法kmp演算法

我們給出目標串味t abbaba,模式串為aba

根據樸素演算法匹配為

t a b b a b a

p a b a

我們可以看到第一趟t0=p0,t1=p1,t2!=p2;但是p0!=t1;由此可以推斷t1=p1!=p0,將p右移一位用t1和p0比較是肯定不相等的,沒必要再進行了,p0=p2,所以同樣p0!=t2;這一趟也不用比較,我們應該直接將p向右移動3位,直接用t3和p0進行比較,這樣匹配就消除了回溯,這就是kmp演算法的思想

一般情況 t=「t0t1t2t3t4……tn-1」,模式p="p0p1p2p3pn-1",根據1中的樸素匹配演算法可以得到從目標串t的第s個位置ts與模式串的第0個位置進行比較,直到在目標t第s+j位置t(s+j)處失配

這是,可以得到  t(s)t(s+1)t(s+2)t(s+3)……t(s+j-1)=p0p1p2p3……p(j-1)              (x)

那麼下一趟應該從目標t中第(s+1)個位置開始匹配

若想成功則有,p0p1p2p3……p(m-1)=t(s+1)t(s+2)t(s+3)………t(s+m);

如果在模式串p中p0p1p2p3……p(j-2)  !=   p1p2p3……p(j-1);                                (y)

則第s+1趟不用比較了

因為由xy式可以得到 p0p1p2p3……p(j-2)  !=t(s+1)t(s+2)t(s+3)……t(s+j-1)

那麼第s+2趟呢,

我們要判斷一下p0p1p2……p(j-3)與p2p3……p(j-1)的關係。

如果p0p1p2……p(j-3)!=    p2p3……p(j-1)

仍有p0p1p2p3……p(j-3)   !=   t(s+2)t(s+3)……t(s+j-1)

這一趟沒必要

我們以此類推直到有乙個k使p0p1……p(k+1)   !=  p(j-k-2)(j-k-1)……p(j-1)

p0p1……p(k)   =  p(j-k-1)(j0k)……p(j-1)

才有p0p1……p(k)  =  t(s+j-k-1)t(s+j-k)……t(s+j-1)

p(j-k-1)   p(j-k)  ……p(j-1)

這時模式串p已經向後滑動了j-k-1位,因此可以直接從t中的t(s+j)與模式中的p(k+1)開始,繼續向下比較。

這個演算法中,目標t在第s趟比較失配後,指標s不必回溯,演算法下一趟從此開始向下進行比較,而在模式p中,掃瞄指標p應退回到p(k+1)處

對於不同的j值,k值只依賴與模式p本身的前j個字元的構成。因此我們可以用乙個next陣列來表示

設模式p=p0p1p2p3……pm-2pm-1,則next陣列的取值如下

-1(j=0)時

next(j)  =        k+1當0<=k

int  fastfind(char  *s,char *str,int next)//s為目標串,str為匹配串

{int p=0;

int t=-1;

int lent=strlnen(s);

int lenp=strlen(str);

while(p

時間複雜度取決於while迴圈,因為無回溯,最多比較lent次,時間複雜度為o(lent)。

那麼問題來了,我們如何得到next陣列。

我們可以用遞推的方法得到next陣列;設next(j)=k;

則0<=kp0p1……p(k=1)=p(j-k-1)p(j-k)……p(j)成立

若p(k+1)=p(j),next(j+1)=k+1=next(j)+1;

若p(k+1) != p(j),在p0p1p2……pk中存在p0p1……ph = p(k-h)p(k-h+1)……p(k);

1  存在h值

next(k)=h;

p0p1……ph = p(k-h)p(k-h+1)……p(k)

= p(j-h-1)p(j-h)……p(j-1)

如果p(h+1)=p(j)

next(j+1)=h+1=next(k)+1=next(next(j))+1;

否則在p0p1……ph中尋找更小的值,next(h)=t;以此下去,直到next(t)=-1,失敗

求next陣列**

void getnext(int next,char *str)

{int j=0;

int k=-1;

int lenp=strlen(str);

next[0]=-1;

while(j

KMP演算法的總結

1 kmp的作用 用於字串匹配,用於查詢乙個字串是否是另乙個字串的子串,可以返回出現的次數以及出現的位置。2 kmp的模板 include include include using namespace std char s1 110 char s2 110 int next 110 void ge...

KMP演算法總結

kmp題目重在理解next陣列的含義 next陣列的作用 next j 記錄模式串中第 j 個字元的最長公共字首長度 重要,這是它的意義所在 第二種理解方式,當模式串與主串失配時,跳回的位置。next len 即字串 0 結束標誌的next值 單個字串匹配時與週期有關 hdu 1711 模板題 33...

KMP演算法總結

kmp演算法是用來實現模式匹配的,其時間複雜度是o m n 具體原理見 其中有用到next陣列來計算子串中公共項的位數,簡單來說,就是子串遇到不匹配時,就查next資料來決定前進幾位 移動位數 已匹配的字元數 對應的部分匹配值 1 要不要減一看next陣列第一位是不是為1,個人覺得加一後是有好處的,...