看毛片算法其實並不難,但是很多人就是看完書還是不懂,覺得難以理解。。。
覺得很多都講得都長篇大論,沒能讓人很清晰的接觸到核心,下面力求精煉的講清楚怎麼看毛片
基本思想如圖:
我們看匹配的過程
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] = -1j==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數組都搞定了,搜索沒什麼好說了的