1. 程式人生 > >KMP演算法中next陣列、nextval陣列的手工計算

KMP演算法中next陣列、nextval陣列的手工計算

剛接觸資料結構,對於其中的一些演算法都不是很瞭解,這幾天剛在學習串的內容,裡面介紹了兩種串的模式匹配演算法,一種是BF演算法(也叫做BoyFriend演算法);另一種是KMP演算法(也叫做“看毛片”演算法)。BF演算法的實現很簡單,很暴力,但是在時間複雜度的限制下,這不是一個很好的演算法。為了提高程式執行的效率,出現了KMP演算法,講真的,演算法真的很難理解(對於大佬來說,這種都是基礎的題目,但對於像我樣的菜雞,就是登天啦~~)。這幾天通過看視訊教程,還有看大佬的部落格,也懂的了一些簡單的方法。

下面跟大家分享下成果吧~

例子:abaabcac
       

1 2 3 4 5 6 7 8
例子 a b a a b c a c
next 0 1 1 2 2 3 1 2


具體步驟:第一位和第二位肯定為0和1
          第三位開始比較前面串的最大真子串,沒有為1
 第四位找:兩位的時候 ab和ba 不一樣
           一位的時候 a 和 a 一樣,長度為1,所以next[4]=1+1=2
以此類推。
總結一下:第一位和第二位固定;
其餘的位數就看它前面的串,找其中長度最大的真子串(注意:找的時候,找兩端,頭在一端,尾在一端,
        找到的串,從左到右讀起來是相同的。比如:ab,ba這兩個就不一樣。相信聰明的你會一聽就明白的),找到next的值為長度加1,未找到值為1。


nextval陣列的計算方法呢,有兩種:一種是靠直接觀察法來算,另一種是依靠next陣列來算。第一種沒怎麼懂,下面講下用next陣列來計算nextval陣列的例子吧。
還是上面的例子:
例子:abaabcac

1 2 3 4 5 6 7 8
例子 a b a a b c a c
next 0 1 1 2 2 3 1 2
nextval 0 1 0 2 1 3 0 2


具體步驟:若前兩位相同,則nextval為0,若不同則為1,第二位的b與第一位的a不同,所以為1
 第三位的時候next值為1,第三位的a與當前next值所對應的值(即是第一位的a)相同,
          所以為0。
 第四位的next值為2,2對應的值為b,與當前的值不相同,nextval值為當前的next值,第四位為2
          第五位的next值為2,2對應的值為b,相同,繼續比,第二位b對應的next值為1,1對應的next值
          為a,不同,結束,所以nextval值為1。
          以此類推,聰明的你肯定明白這其中的規律的。
總結下規律:第一位的nextval值肯定為0,第二位,觀察第一位,相同為0,不同為1。剩下的求nextval:
若當前值與當前next所對應的值不同,則直接為當前next值;若相同,則繼續查詢對應的next值,有不同的就把對應的next值給nextval(正如上面的第五位查詢),否則為0。
呼呼~說了這麼多,你明白了嗎?

下面貼上程式碼,供大家檢驗,對比。

#include<bits/stdc++.h>
using namespace std;
#define maxn 255
typedef struct
{
    char ch[maxn+1];
} SString;
void Init(SString &S)
{
    char str[maxn];
    cin>>str;
    S.ch[0] = strlen(str);//用第一個位置,存陣列的長度
    for(int i=0;str[i];i++)
        S.ch[i+1] = str[i];
}
void get_nextval(SString &S1,int nextval[])
{
    int i=1,j=0;
    nextval[1] = 0;
    while(i<S1.ch[0])
    {
        if(j==0||S1.ch[i]==S1.ch[j])
        {
            i++;
            j++;
            if(S1.ch[i]!=S1.ch[j])nextval[i] = j;
            else
                nextval[i] = nextval[j];
        }
        else
            j = nextval[j];
    }
    for(int k=1; k<=S1.ch[0]; k++)
        cout<<nextval[k]<<' ';
}
void get_next(SString &T,int next[])
{
    int i=1,j=0;
    next[1] =0;
    while(i<T.ch[0])
    {
        if(j==0||(T.ch[i]==T.ch[j]))
        {
            ++i;++j;
            next[i]=j;
        }
        else
            j = next[j];
    }
     for(int k=1;k<=T.ch[0];k++)
        cout<<next[k]<<' ';
}

int main()
{
    SString S1;
    Init(S1);
    int next[maxn];
    ///Get_next(S1,next);
    get_next(S1,next);
    cout<<endl;
    get_nextval(S1,next);
}

歡迎大佬指教~