1. 程式人生 > >字串模式匹配(簡單模式匹配演算法與KMP演算法)(一)

字串模式匹配(簡單模式匹配演算法與KMP演算法)(一)

一般的字串模式匹配演算法是類似下面的逐次匹配,舉例說明如下

主串s=ababcabcacbab

從串t=abcac

一般匹配方法如下圖所示

圖片

程式碼如下

int index(string s,string t)
{
    int i=0,j=0;
    int l1=s.length();
    int l2=t.length();
    while(i<=l1-1&&j<=l2-1)
    {
        if(s[i]==t[j])
        {
            ++i;
            ++j;
        }
        else
        {
            if(j==0)
            {
                ++i;
            }
            else
            {
                i=i-j+2;
                j=0;
            }

        }
        //cout<<"i="<<i<<"j="<<j<<endl;
    }
    if(j>l2-1) return i-l2;
    else return 0;
}

這樣算下來的時間複雜度是O(l1*l2),因為每次只要中間發生字串s[i]和t[j]不相等,這種演算法會把字串t的索引置為0,而主串s也是從之前開始匹配的i加一個1,其實我們可以發現,中間有些比較是不必要的,比如從第三趟比較就可以看出主串中第4,5,8個字串是‘b’,'c','a',(對應模式串中的第2,3,4個字元)。而模式串t中第一個字元是a,所以其實不需要和這幾個字元相比較了,只需要將模式向右滑動3個字元即可。這樣的匹配過程中,實際上主串i沒有回溯,只是模式串的j在變化,就降低了時間複雜度為O(l1+l2),這也就是kmp演算法。

kmp演算法每趟比較過程讓模式串向後滑動一個合適的位置,這個合適的位置我們可以算出來,一般稱這個位置叫next表。

先寫出next表的定義,接下來再解釋為什麼這樣定義

結合這個圖來解釋

先說一下,上面兩個圖中的S0和T0分別代表的是兩個穿的長度,真正的字串都從下標1開始。

1)當j=1時,也就是說模式串的第一個字元就與當前位置s對應的字元不同,此時主串的下標應該+1,再和模式串第一個字元進行比較;

2)當兩個串匹配到此處時,前j-1個字元都是匹配的,到了第j個字元就不同了,此時需要把字串t向右移動max{k}個位置。

這個k應該滿足1<k<j並且p1...pk-1=pj-k+1...pj-1.k的值可能有多個,為了不使向右移動丟失可能的匹配,選擇最大的一個k,也就是max{k},其最大值為j-1;

3)除了上面兩種情況,發生匹配時,主串指標i不回溯,在最壞情況下,模式串從第1個字元開始與主串第i個字元比較,以便不丟失可能的匹配。

上面講解的next函式表的定義,然後下面是求next函式表的程式碼以及實現kmp演算法。篇幅有點長,轉到下一篇講。