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;
}

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