1.引入next数组
数组含义:对于一个字符串ababaab
next[0],next[1],next[2],next[3]...分别表示a,ab,aba,abab,的最长前缀和最长后缀相同的长度他们是
, ,a ,ab,
值分别为 -1,-1,0,1 -1表示不存在,0表示存在长度为1,2表示存在长度为3
2.求一个字符串的next数组
对于一个字符串
ababab 他有相同的地方就是第一个a等于第三个a,第二个b等于第四个b。。。。。
此时他的next[5]=3;
现在增加一个字母,只要检测他是否等于str[k+1]即是str[1]
若是,k在原来基础上+1
若不等于
a a b a a b c d e a a b a a [f]
只能在前缀里找,对前缀求next[],得出最长前后缀相同的长度。然后double的前缀就和
[]前面的字母相同,现在只要str[k+1]==f就找到了最长的。
若还是不等对doule的前缀再找前缀。
程序实现
void cal_next(char *str, int *next, int len)
{int i,k;
next[0]=0;
k=-1;
for(i=1;i<len;i++){
while(k>-1&&str[k+1]!=str[i])
{k=next[k];}
if(str[k+1]==str[i])
{k=k+1;}
next[i]=k;
}
return 0;
}
3.通过next函数实现kmp算法
int KMP(char *str, int slen, char *ptr, int plen){
int *next = new int[plen];
cal_next(ptr, next, plen);//计算next数组
int k = -1; for (int i = 0; i < slen; i++) //k初始化为-1
{ while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)
k = next[k];//往前回溯
if (ptr[k + 1] == str[i]) //首先k=-1在这里变成0;如果一直相等不做处处理,知道出现两种情况1.不相等了
k = k + 1; //不相等了,则next[k]表示是后缀有几个已经在str里然后直接赋值给k,再此基础上继续 2.ptr遍历完了
if (k == plen-1)//说明k移动到ptr的最末端
{ //cout << "在位置" << i-plen+1<< endl;
k = -1;//重新初始化,寻找下一个
//i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在
两个匹配字符串可以部分重叠),感谢评论中同学指出错误。
return i-plen+1;//返回相应的位置 } }
return -1; }