必懂kmp

看毛片算法其實並不難,但是很多人就是看完書還是不懂,覺得難以理解。。。

覺得很多都講得都長篇大論,沒能讓人很清晰的接觸到核心,下面力求精煉的講清楚怎麼看毛片

基本思想如圖:

我們看匹配的過程

Ti-j......Ti.........

P0.......Pj...

(留意是匹配了j個字符,匹配到第j+1個字符)

當匹配到Ti和Pj時,Ti != Pj,那麼就要移動模式串了,而我們這時知道的信息有:

Ti-j......Ti-1 == P0.......Pj-1 (j個字符相等) -------------[1]

我們設下一個要和Ti進行比較的字符是Pk(就是說移動了j-k個位),那麼前提是

P0......Pk-1 == Ti-k....Ti-1 (k個字符相等)-------------[2]

滿足這個條件的k可能不止一個,我們肯定要選擇最大的k,這樣纔不會漏掉可能的情況

然後聯立[1][2]兩條式子,有:

P0......Pk-1 == Pj-k.......Pj-1 (k個字符相等)-------------[3]

由[3]可以看出,前k個字符和後k個字符相等,就是說,我們可以從模式串本身去得到這些移動的信息,而這個信息就是:

對於Pj失配時,在字串P0....Pj-1中,有最大的k,使前k個字符和後k個字符相等,k<=j-1,Pk!=Pj

我們設k=next[j],即next[j]代表P0....Pj-1中的最大的k(Pj失配時,下一個應該和Ti比較的是Pnext[j]

明顯,我們有基本情況:

  • j==0
    next[j] = -1

  • j==1 //這個情況其實是用下邊的規則統一遞推出來,寫上去只是容易理解清晰一點
    Pj != Pj-1 next[j] = 0
    Pj == Pj-1 next[j] = -1

然後就是遞推的關係,這個關係就是看毛片的難點所在,因爲這個遞推關係不是單純和其他的next值有關,而是要用一個變量,記錄P0....Pj-1中最大的k,使前k個字符和後k個字符相等,k<=j-1,且Pk!=Pj,因爲最後的這個條件,所以我們不能直接用之前的next去推導。設那個記錄的變量是i,那麼我們有如下的關係:

  • Pj+1==Pi+1 ++i , ++j; //++i是更新相等的前後綴的長度
    next[j] = next[i];

  • Pj+1!=Pi+1 ++i,++j;
    next[j] = i;
    do
    i=next[i]; //保證了Pnext[i] != Pi
    while(i>=0 && Pj != Pi);

第一條規則,因爲條件,明顯就有next[j]=next[i]

第二條規則,也是因爲條件,明顯有next[j]=i,難點在於更新i的值

結合這些條件,我們就可以寫出球next數組的函數了

void getnext(char  *P,int  *next)
{
    int len = strlen(P),i=-1,j=0;
    next[0]  =  -1; 

    while(j<len)  {
        ++j;++i;
        next[j]  = i;
        if(P[i]==P[j])  next[j]  =  next[i];
        while(i>=0  && P[j]!=P[i]) i =  next[i];
    }   
}

next數組都搞定了,搜索沒什麼好說了的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章