個人學習 -- KMP算法

如此愚鈍 一天才學會

KMP算法的思想就是,如果已經匹配的模式串內部有重複的部分,那麼我們移動的時候就能多移動幾步,而且由於模式串的大小都是固定的,所以我們可以提前的求出有哪些部分是重複的。
這裏說的重複是指,前綴子串和後綴子串
舉個例子: e x a m p l e

  • 前綴子串: e , ex, exa, exam , examp , exampl
  • 後綴子串: e , le , ple, mple , ample , xample

找到它們之間的公共部分記錄在next數組裏面,其實next數組是最難求的。


#include <iostream> 
#include <string>

class KMP {
public:
    KMP(const std::string &str) \ 
        : str_(str) {
        next_ = new int[str.size()];
    }
    /*        | <- 壞字符
    a b a b a e s d f ...
    a b a b a c e b 
      next_[4] = 2 
      3  
        a b a b a c   
    */
    int find(const std::string &mod) const {
        int j = 0;
        init_next(mod);
        for(int i = 0; i < str_.size() ; i++) {
            while(j > 0 && str_[j] != mod[i]) { //如果不相等的話就向後移動
                j = next_[j - 1]; //將模式串移動到前一位對應的位置上面
            }
            if(str_[j] == mod[i]) { //如果相等的話就向下走
                j ++;
            }
            if(j == mod.size()) {
                return i - mod.size() - 1; //找到合適的
            }
        }
        return -1;
    }
    //前綴結尾字符下標 最長可匹配前綴子串結尾的字符下標。
    void init_next(std::string &mod) const {
        next_[0] = 0;
        int j = 0;
        for(int i = 1; i < mod.size() ; ) {
            if(mod[i] == mod[j]) {
                next_[i] == ++j;
                ++ i;
            }else {
                if(j == 0) //如果j已經退回到0 還是不相等
                {
                    next_[i] = 0;
                    i ++;
                }
                else {
                    while(mod[i] != mod[j] ) {
                        j = next_[j - 1]; //j變爲壞字符前面存儲的值 
                    }
                }  
            }
        }
    }
private:
    int *next_;
    std::string &str_;
};

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