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);
}
歡迎大佬指教~