算法思想:i不回溯,当i所指主串字符与j所指主串字符不相等时,令j=next[j]即可
(1)基本方法(找next)
next[j]的求法见下图:
代码:
#include<iostream>
#include<cstring>
using namespace std;
#define MAXSIZE 255
#define OVERFLOW -2
typedef struct{
char *ch;
int length;
}SString;
//初始化
int Init(SString &S){
S.ch=new char[MAXSIZE+1];
if(!S.ch) return OVERFLOW;
S.length=0;
return 1;
}
//赋值
void StrAssign(SString &S,char c[]){
S.ch[0]=strlen(c);
for(int i=1;i<=strlen(c);i++){
S.ch[i]=c[i-1];
S.length++;
}
}
//显示
void Show(SString S){
for(int i=0;i<=S.length;i++){
cout<<S.ch[i]<<" ";
}
cout<<endl;
}
//找next
void get_next(SString T,int *next){
int i=1,j=0;
next[1]=0;
while(i<=T.length){
if(j==0||T.ch[i]==T.ch[j]){
++i;++j;
next[i]=j; //记下next[i]值
}
else j=next[j]; //j回溯
}
}
//匹配
int Index_KMP(SString S,SString T){
int i=1,j=1;
int next[255];
get_next(T,next); //取得next数组
while(i<=S.length&&j<=T.length){
if(S.ch[i]==T.ch[j]){
++i;++j;
}
else j=next[j]; //字符不相等,修正j,重新匹配
}
if(j>T.length) return i-T.length; //匹配成功,返回索引
else return 0; //匹配失败
}
int main(){
SString S,T;
Init(S);
Init(T);
char s[]="aaaaab";
char t[]="aaab";
StrAssign(S,s);
StrAssign(T,t);
Show(S);
Show(T);
int num=Index_KMP(S,T);
cout<<num<<endl;
return 1;
}
运行结果:
(2)KMP改进(找nextval)
避免相同字符反复比较![](https://img-blog.csdnimg.cn/0b872bd950f54eec9d42fe61f3faa844.jpeg)
关键代码如下,其他不变
//找next
void get_nextval(SString T,int *nextval){
int i=1,j=0;
nextval[1]=0;
while(i<=T.length){
if(j==0||T.ch[i]==T.ch[j]){
++i;++j;
if(T.ch[i]!=T.ch[j]){ //当前字符i与前缀j不相等
nextval[i]=j; //更新nextval值
}
else nextval[i]=nextval[j]; //相等,回溯
}
else j=nextval[j]; //修正j
}
}
//匹配
int Index_KMP(SString S,SString T){
int i=1,j=1;
int nextval[255];
get_nextval(T,nextval);
while(i<=S.length&&j<=T.length){
if(S.ch[i]==T.ch[j]){
++i;++j;
}
else j=nextval[j]; //修正j
}
if(j>T.length) return i-T.length;
else return 0;
}