KMP算法基本思想與實現

/**
KMP算法
算法思想:
T0....T(j-i)......T(j-1)   Tj
        =             =     !=
      p0            P(i-1)  Pi
即在比較的過程中有
P(0...i-1) = T(j-i....j-1) 再往下匹配時  Pi =!Tj
如果找到K值使
P(0..i-k-1) = p(k..i-1)
這樣字符創P可以移動K位

因爲P(k..i-1)與Tj-1前面的i-1-K爲相等
所以P(0..i-k-1)也與Tj-1前面的i-1-K爲相等
因此只需要比較P(i-k) 和Tj就行了
*/
#include <iostream>
#include <string>
using namespace std;

/**
尋找模式串P每個字符的特徵數
即每個字符前P(0...i-1)的最大相同前綴子串和後綴子串
Next(i) =   -1             當i = 0使
            max{k:0 < k < i && P(0...k-1) = P(i-k...i-1) }  K存在
            0                                               K不存在
*/
int * findNext(string P)
{
    int i = 0;
    int m = P.length();
    int * Next = new int[m];
    Next[0] = -1;
    int k = -1;
    //從開始0-m-1循環,計算 i= 0...m-1的next的值
    while(i < m)
    {
        //求最大的首位子串
        while(k >= 0 && P[i] != P[k])
        {
            /**用到前邊所求的next的值
               因爲是要每次都是從P的開始位置匹配
               next[i]的值就是在第i個字符前面串的最大相同前綴和後綴子串
               而P[k]是P的第k個字符,現在P[k]和P[i]不相等,我們應該從第
               k的字符的最大相同前綴和後綴子串的位置開始重新匹配
               而第K個字符的最大相同前綴和後綴子串的位置是next[k]
               就是相當於把P串看成要匹配的串
            */
            k = Next[k];
        }
        i ++;
        k ++;
        if(i == m) break;
        //如果P[i] 和 P[k] 相等,優化
        /**如果P[i] 和 P[k] 相等
        則P[k]也不會和Tj相等
        還需要向右移動
        */
        if(P[i] == P[k])
        {
            Next[i] = Next[k];
        }
        else
            Next[i] = k;
    }

    return Next;
}

int KMP(const string & T ,const string & P , int * Next)
{
    int tLen = T.length();
    int pLen = P.length();
    int i = 0;
    int j = 0;

    if(tLen < pLen) return -1;
    while(i < tLen && j < pLen)
    {
        if(j == -1 || T[i] == P[j])
        {
            i ++;
            j ++;
            //cout<<"j:"<<j<<endl;
        }
        else
        {//如果不匹配,返回到最大前綴後綴子串處去匹配
            j = Next[j];
        }
    }
    //最後檢驗結果,若果j的值大於P的長度是說明子串的位置已經找到
    if(j >= pLen)
    {
        return (i - pLen + 1);
    }
    else return -1;

}
int main()
{
    //cout << "Hello world!" << endl;
    string T = "abcdaabcab";
    string P = "abc";
    int * Next = findNext(P);

    for(int i = 0 ; i < P.length() ; i ++)
    {
        cout<<Next[i]<<"  ";
    }
    cout<<endl;
    int j = KMP(T,P,Next);
    cout<<j<<endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章