KMP算法中next數組及改進的kmp算法nextval數組的手工計算方法

KMP算法是模式匹配專用算法。

它是在已知模式串的next或nextval數組的基礎上執行的。如果不知道它們二者之一,就沒法使用KMP算法,因此我們需要計算它們。

KMP算法由兩部分組成:

第一部分,計算模式串的next或nextval數組。

第二部分,利用計算好的模式串的nextval數組,進行模式匹配。

    KMP算法中有next數組和nextval數組之分。 他們代表的意義和作用完全一樣,完全可以混用。 唯一不同的是,next數組在一些情況下有些缺 陷,而nextval是爲了彌補這個缺陷而產生的。

    筆試題目中經常要求計算KMP算法的next數組,網上有很多討論的文章,但是感覺都講的不太清楚,特別是在如何手工計算這一方面,所以今天特別整理了一下放到這裏,一來備忘,二來也希望給有緣人帶來一些方便。

一、求解next(總結:同加1,不同即1)

步驟:next數組值的程序設計求解方法:首先可以肯定的是第一位的next值爲0,第二位的next值爲1,後面求解每一位的next值時,根據前一位 進行比較。首先將前一位與其next值對應的內容進行比較,如果相等,則該位的next值就是前一位的next值加上1;如果不等,向前繼續尋找next值對應的內容來與前一位進行比較,直到找到某個位上內容的next值對應的內容與前一位相等爲止,則這個位對應的值加上1即爲需求的next值;如果找到 第一位都沒有找到與前一位相等的內容,那麼需求的位上的next值即爲1。

舉例:
模式串  a  b  a  a  b  c  a  c
next值  0  1  1  2  2  3  1  2
1.前兩位必爲0,1。
2.計算第三位的時候,看第二位b的next值,爲1,則把b和1對應的a進行比較,不同,則第三位a的next的值爲1,因爲一直比到最前一位,都沒有發生比較相同的現象。
3.計算第四位的時候,看第三位a的next值,爲1,則把a和1對應的a進行比較,相同,則第四位a的next的值爲第三位a的next值加上1,爲2。因爲是在第三位實現了其next值對應   
的值與第三位的值相同。
4.計算第五位的時候,看第四位a的next值,爲2,則把a和2對應的b進行比較,不同,則再將b對應的next值1對應的a與第四位的a進行比較,相同,則第五位的next值爲第二位b的next值加上1,爲2。因爲是在第二位實現了其next值對應的值與第四位的值相同。
5.計算第六位的時候,看第五位b的next值,爲2,則把b和2對應的b進行比較,相同,則第六位c的next值爲第五位b的next值加上1,爲3,因爲是在第五位實現了其next值對應的值與第五位相
6.計算第七位的時候,看第六位c的next值,爲3,則把c和3對應的a進行比較,不同,則再把第3位a的next值1對應的a與第六位c比較,仍然不同,則第七位的next值爲1。
7.計算第八位的時候,看第七位a的next值,爲1,則把a和1對應的a進行比較,相同,則第八位c的next值爲第七位a的next值加上1,爲2,因爲是在第七位和實現了其next值對應的值與第七位相同。

二、求解nextval(總結:同爲0,不同爲1)

       求nextval數組值有兩種方法,一種是不依賴next數組值直接用觀察法求得,一種方法是根據next數組值進行推理,兩種方法均可使用,視更喜歡哪種方法而定。                                                                                    本文主要分析nextval數組值的第二種方法:
                                                                      模式串      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

                                                                             1.第一位的nextval值必定爲0,第二位如果於第一位相同則爲0,如果不同則爲1。
                                         2.第三位的next值爲1,那麼將第三位和第一位進行比較,均爲a,相同,則,第三位的nextval值爲0。
                        3.第四位的next值爲2,那麼將第四位和第二位進行比較,不同,則第四位的nextval值爲其next值,爲2。
                     4.第五位的next值爲2,那麼將第五位和第二位進行比較,相同,第二位的next值爲1,則繼續將第二位與第一位進行比較,不同,則第五  位的nextval值爲第二位的next值,爲1。
                                                                        5.第六位的next值爲3,那麼將第六位和第三位進行比較,不同,則第六位的nextval值爲其next值,爲3。
                     6.第七位的next值爲1,那麼將第七位和第一位進行比較,相同,則第七位的nextval值爲0。
                               7.第八位的next值爲2,那麼將第八位和第二位進行比較,不同,則第八位的nextval值爲其next值,爲2。
三、next和nextval比較

Next數組的缺陷舉例如下:

比如主串是“aab…..”  省略號代表後面還有字符。

 模式串“aac”

通過計算aac的next數組爲012(另外,任何字符串的第二位字符的next總是1,因此你可以認爲他固定爲1)

當模式串在字符c上失配時,會跳到第2個字符,然後再和主串當前失配的字符重新比較,即此處用模式串的第二個a和主串的b比較

即 aab                   aac

顯然a也不等於b。然後 會跳到1,接着比,然後又失配,直到最後才使主串後移一位。

而“aac”的nextval數組爲002 當在c失配時會跳到2,若還失配就直接跳到0,比next數組少比較了1次。

在如果模式串很長的話,那可以省去很多比較,因此你應該使用nextval數組。


四、嚴蔚敏

上:http://v.youku.com/v_show/id_XODYxNjExODQ=.html     第 34分鐘開始 

    下:http://www.56.com/u28/v_NjAwMzA0ODA.html  

五、代碼實現:
 public static void main(String [] args) throws IOException{//main函數,輸入主串和模式串
        System.out.print("請輸入主串:");
        Scanner sn1 = new Scanner(System.in);
        String s1 = sn1.next();
        System.out.print("請輸入模式串:");
        Scanner sn2 = new Scanner(System.in);
        String s2 = sn2.next();
        char [] s3 = s1.toCharArray();
        char [] s4 = s2.toCharArray();
        System.out.print(KMP_test(s3,s4));
    }
    
    public static int KMP_test(char [] s, char [] t){// 主串順序匹配
        int [] next = next(t);
        int i = 0, j = 0;
        while(i
            if(j == -1 || s[i] == t[j]){
                ++i;
                ++j;
            }else{
                j = next[j];
            }
        }
        System.out.println(i);
        if(j
            return 0;
        }else{
            return i-t.length;
        }
    }
    
    public static int [] next(char [] t){// next函數求解
        int i = 0, j = -1;
        int [] next = new int[t.length];
        next[0] = -1;
        while(i
            if(j == -1 || t[i] == t[j]){
                ++i;
                ++j;
                next[i] = j;
            }
            else
                j = next[j];
        }
        System.out.println(Arrays.toString(next));
        return next;
    }
對於改進的KMP算法,只需要把next函數換爲nextval函數就行了
    public static int [] next(char [] t){
        int i = 0, j = -1;
        int [] next = new int[t.length];
        next[0] = -1;
        while(i
            if(j == -1 || t[i] == t[j]){
                ++i;
                ++j;
                if (t[i] != t[j]) {  
                    next[i] = j;  
                } else {  
                    next[i] = next[j];  
                } 
            }
            else
                j = next[j];
        }
        System.out.println(Arrays.toString(next));
        return next;
    }


發佈了134 篇原創文章 · 獲贊 240 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章