采用了next[0]=-1的形式,字符串开始位置都是从0开始
代码:
#include <iostream>
#include <string.h>
#include <iomanip>
using namespace std;
const int maxn=110;
int next[maxn];
int nextval[maxn];
string s1;//主串
string s2;//模式串
int len1;//主串的长度
int len2;//模式串的长度
void getNext(string s2,int next[])
{
int i=0,j=-1;
next[0]=-1;
while(i<len2)
{
if(j==-1||s2[i]==s2[j])//j==-1,指的是回溯到开头j=next[0]=-1,相当于第一个字母的位置,当前位置前面没有任何子串可以和字符串的开头子串相匹配,就用字符串的第一个字母与当前位置相匹配
{
++i;
++j;//j在++之前指的是与当前位置相邻的前面有j个字母和字符串开头的字母相匹配,比如abbabc,i=5(从0开始),s[5]=c,j=2,表示的是c前面的ab与字符串前面两个字母相匹配(ab)
next[i]=j;
}
else j=next[j];
}
}
void getNextval(string s2,int nextval[])
{
int i=0,j=-1;
nextval[0]=-1;
while(i<len2)
{
if(j==-1||s2[i]==s2[j])
{
++i;++j;
if(s2[i]==s2[j])
nextval[i]=nextval[j];
else
nextval[i]=j;
}
else
j=nextval[j];
}
}
int kmp(string s1,string s2,int nextval[])
{
int i=0,j=0;
while(i<len1&&j<len2)
{
if(s1[i]==s2[j]||j==0)
{
++i;
++j;
}
else
j=next[j];
}
if(j==len2)
return i-j;
return -1;
}
int main()
{
cout<<"输入主串:"<<endl;
cin>>s1;
cout<<"输入模式串:"<<endl;
cin>>s2;
len1=s1.length();
len2=s2.length();
getNext(s2,next);//获得next[]值
cout<<"模式串的next[]值为:"<<endl;
for(int i=0;i<len2;i++)
cout<<setiosflags(ios::left)<<setw(3)<<next[i]<<" ";
cout<<endl;
getNextval(s2,nextval);//获得nextval[]值
cout<<"模式串的nextval[]值为:"<<endl;
for(int i=0;i<len2;i++)
cout<<setiosflags(ios::left)<<setw(3)<<nextval[i]<<" ";
cout<<endl;
cout<<"模式串在主串中的匹配位置为:"<<endl;
int p=kmp(s1,s2,nextval);
if(p!=-1)
cout<<p<<endl;
else
cout<<"匹配不成功!"<<endl;
return 0;
}
运行截图: