kmp算法精髓在于next数组(我这里是nextval),而next数组的构造精髓在于模式串的自身匹配。
构造next数组:
首先 置next[0]为-1,假设对于模式串位置为i的字符匹配失败,对该字符前的字符串进行前缀和后缀的最大匹配,如果匹配失败字符和匹配的最大前缀(前缀和后缀匹配后得出)后面的字符相等, nextval[i]=nextval[j];//将模式串移到nextval[j]位置,与目的字符继续匹配 若不相等:nextval[i]=j;//将模式串移到j位置,与目的字符继续匹配
#include <iostream>
#include <string>
using namespace std;
int KMP_Search(string & src,string &modeStr);
void GetNextval(const string src,int *nextval );
int main()
{
cout<<KMP_Search(string("abcdefgdefg"),string("de"));
return 0;
}
void GetNextval(const string src,int *nextval )
{
const int srcLen=src.length();
int i=0;
int j=-1;
nextval[0]=-1;
while (i<srcLen-1)
{
if (j==-1 || src[i]==src[j])
{
++j;
++i;
if (src[i]==src[j])
nextval[i]=nextval[j];//将模式串移到nextval[j]位置,与目的字符继续匹配
else
nextval[i]=j;//将模式串移到j位置,与目的字符继续匹配
}
else
j=nextval[j];
}
}
int KMP_Search(string &src,string &modeStr)
{
if (modeStr=="" || src=="")
return -1;
const int srcLen=src.length();
const int modeStrLen=modeStr.length();
//初始化next数组
int *nextval=new int[modeStrLen];
GetNextval(modeStr,nextval);
for (int i=0,j=0; i<srcLen;)
{
if (src[i]==modeStr[j])
{
++i;
++j;
if (j==modeStrLen)
{
delete nextval;
return i-j;
}
}
else
{
if (nextval[j]==-1)
{
j=0;
++i;
}
else
j=nextval[j];
}
}
delete nextval;
return -1;
}