1. 程式人生 > >超詳細理解:kmp演算法next陣列求解過程和回溯的含義

超詳細理解:kmp演算法next陣列求解過程和回溯的含義

前言

KMP演算法是用來求一個較長字串是否包含另一個較短字串的演算法。具體演算法下一篇寫吧,這篇主要解釋next陣列的求解。

程式碼

程式碼應該都看過了,先貼在這裡,其中最難理解的地方就是求next陣列,以及k往前回溯,這也是寫本文的目的。

int *next = new int[length];
//這裡的str是被包含的較短字串,length是這個字串的長度。
void next(char *str, int *next, int length)
{
    next[0] = -1;
    int k = -1;
    for (int q = 1; q <= length-1; q++)
    {
        while (k >
-1 && str[k + 1] != str[q]) { k = next[k];//往前回溯 } if (str[k + 1] == str[q])//如果相同,k++ { k = k + 1; } next[q] = k; } }

理解

這裡是用被包含的較短字串,自己與自己匹配,求得next陣列,然後再進行演算法的後續步驟。

next陣列中儲存的是這個字串字首和字尾中相同字串的最長長度。比如abcdefgabc,字首和字尾相同的是abc,長度是3。

next[i]儲存的是string中前i+1位字串字首和字尾的最長長度。如abadefg,next[2]存的是aba這個字串字首和字尾的最長長度。

但是這裡為了和程式碼相對應,將-1定義為相同長度為0,0定義為相同長度為1,……依次類推

這裡用一個比較明顯的字串abababac來做例子,先建立一個和字串長度相同的陣列next。第一位設為-1。
01

所以向後移一位開始比較
02

a和b不同,next第二位寫-1
03

再向後移一位
04

a和a相同,next陣列存前一個k=-1加1等於0.
05

再比較下一位,相同就比前一個加一。
06

到第7位時,c和b不再相等,這時就用到了回溯!!!先看下一次比較時,應該移動到哪裡。
07

原因要再回來看上一次比較,上一次比較相同長度為5。
08

看這5個字串相同的前後綴的長度,即next[4]中儲存的值:2再加1,因為這5個字串就是str的前五個字串!
09

所以k先回溯到2,再比較下一個字元是否相同,這裡是比較c和b,不同,再回溯,這次前面剩下aba三個字元,k=next[2]=0,即前後綴還有一個字元相同,所以應該後移到下圖位置。
10

再比較c和b,還不同,再回溯,k=next[0]=-1,然後next[7]=-1,這樣就求出了next陣列了。
11

我感覺看到這裡,應該就真正理解了next陣列求解和回溯了吧,之後的演算法其實和求next陣列差不多,本來想寫一下,發現這篇文章寫的很好,完整演算法看它就好了。