KMP(字串匹配)

來源:互聯網
上載者:User

標籤:style   blog   http   color   os   strong   io   資料   

1、KMP是一種用來進行字串匹配的演算法,首先我們來看一下普通的匹配演算法: 

現在我們要在字串ababcabcacbab中找abcac是不是存在,那麼傳統的尋找方法就是一個個的匹配了,

 

經過六趟匹配之後,終於匹配上了。現在是資料比較小的時候,大家可能沒有什麼感覺,如果我們的資料是百萬層級的,那用這種方法無疑複雜度太高了,很難接受。

 

2、模式比對的一種改進演算法: 

這種改進演算法由D.E.Knuth與V.R.Pratt和J.H.Morris同時發現的,因此人們稱他為克努特-莫裡斯-普拉特操作(簡稱KMP演算法)。此演算法可以在O(n + m)的時間數量級上完成串的模式比對操作。其改進在於:每當一趟匹配過程中出現字元比較不等時,不需要回溯i指標,而是利用已經得到的“部分匹配”結果將模式向右“滑動”儘可能遠的一段距離後,繼續進行比較。下面先從具體的例子看起。

回顧上面的傳統的匹配過程,在第三趟的匹配中,當i = 7、j = 5字元比較不等時,又從i = 4、j = 1重新開始比較。然後,經仔細觀察發現,在i = 4和j = 1,i = 5和j = 1以及i = 6和j = 1這3次比較都是不必進行的。因為從第三趟部分比配結果就可得出,主串中第4、5和6個字元必然是‘b‘、‘c‘和‘a‘(即模式串中的第2、3、和4個字元)。因為模式中的第一個字元是a,因此它無需再和這3個字元進行比較,而僅需要將模式串向右滑動3個字元的位置繼續進行i = 7、j = 2時字元比較即可。同理,在第一趟匹配中出現字元不等時,僅需要將模式向右移動兩個字元的位置繼續進行i = 3、j = 1時的字元比較。由此,在整個匹配過程中,i指標沒有回溯,4.4所示。

3、KMP 

此時我們構建一個next[]數組,這個數組的意思就是,當主串中的第i個字元與模式串中的第j個字元失配時,模式串中的next[j]個字元與第i個字元繼續進行比較,顯然複雜度提高了很多。

符合代碼:

int index_KMP(){    int stra = strlen(a);    int strb = strlen(b);    int i = -1,j = -1;    while(i < stra && j < strb)    {        if(j == -1 || a[i] == b[j])        {            i++;j++;        }        else        {            j = next[j];        }    }    if(j >= strb)    {//在a中找到了b字串        return 1;    }    return 0;}
View Code

 

4、求next數組: 

KMP演算法實在已知模式串的next函數值的基礎上執行的,那麼,如何求得模式串的next函數值呢?

從上述討論可見,此函數值僅取決於模式串本身和相匹配的主串無關。我們可從分析其定義出發用地推的方法求得next函數值。

設next[j] = k,這表明在模式串中存在下列關係:‘p1....pk-1‘ = ‘pj-k+1....pj-1‘。其中k為滿足1 < k < j的某個值,此時的next[j + 1] = ?可能有兩種情況:

(1)若pk = pj,則表明模式串中‘p1....pk‘ = ‘pj-k+1....pj‘

這就是說next[j+1] = k+1,即next[j + 1] = next[j] + 1。

(2)若pk != pj,則表明在模式串中‘p1....pk’ != ‘pj-k+1....pj‘

此時可把求next函數值的問題看成是一個模式比對的問題,整個模式串既是主串又是模式串,而當前在匹配過程中,已有pj-k+1=p1,pj-k+2=p2,...,pj-1=pk-1,則當pj!=pk時應將模式向右滑動至模式中的第next[k]個字元和主串的第j個字元相比較。若next[k] = k‘,且pj = pk‘,則說明在主串中的第j+1個字元之前存在一個長度為k’(即next[k])的最長子串,和模式串中從首字元起長度為k‘的子串相等,即‘p1...pk‘‘ = ‘pj-k+1...pj‘   (1 < k‘ < k < j)      (4 - 10)

這就是說next[j + 1] = k‘ + 1即next[j + 1] = next[k] + 1。

同理,若pj!=pk‘,則將模式繼續向右滑動直至將模式中第next[k‘]個字元和pj對齊,....,依次類推,直至pj和模式中某個字元匹配成功或者不存在任何k‘(1 < k‘ < j)滿足等式(4 - 10) 則next[j + 1] = 0。

代碼:

void get_next(){    next[0] = -1;    int j = -1;    int i = 0;    int str = strlen(b);    while(i < str - 1)    {        if(j == -1 || b[i] == b[j])        {            next[++i] = ++j;        }        else        {            j = next[j];        }    }}
View Code

 

5、給出一份完整代碼: 

#include<iostream>#include<cstdio>#include<cstring>using namespace std;char a[1000];char b[1000];int next[1000];void get_next(){    next[0] = -1;    int j = -1;    int i = 0;    int str = strlen(b);    while(i < str - 1)    {        if(j == -1 || b[i] == b[j])        {            next[++i] = ++j;        }        else        {            j = next[j];        }    }}int index_KMP(){    int stra = strlen(a);    int strb = strlen(b);    int i = -1,j = -1;    while(i < stra && j < strb)    {        if(j == -1 || a[i] == b[j])        {            i++;j++;        }        else        {            j = next[j];        }    }    if(j >= strb)    {//在a中找到了b字串        return 1;    }    return 0;}int main(){    while(scanf("%s%s",a,b)!=EOF)    {        get_next();        if(index_KMP())        {            printf("YES\n");        }        else        {            printf("NO\n");        }    }    return 0;}
View Code

 

運行結果:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.