现在看来下面写的不是很好,以后在整理
next数组的求法及原理应该注意的是由于在编号的时候将next中的第一个元素编排成0了,因此next[i]其实记录不但是与从开头的对称数,并且是i+1所要匹配的元素的下标
当出现失配的情况时,如下图在str[14]!=str[7]的时候,就接着进行如下操作
也就是说再接着从失配的位置(7)之前的那个字母在重新匹配,但是这时实际应该是从开头的那个位置来说的所以是匹配的3位置,而不是6位置,再好好想想。。。
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
char str[1000];
cin>>str;
int next[1000];
int len=strlen(str);//模式字符串长度。
next[0]=0;
for(int i=1; i<len; i++)
{
int k=next[i-1];
while( str[i] != str[k] && k!=0 )
k=next[k-1]; //继续递归
if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
next[i]=k+1;
else
next[i]=0; //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
}
return 0;}
较为低级的求next数组的方法
//这中算法是字母的下标和next数组中的下标正好相等了,也就是说这样求的next数组所储存的值
//正好相当于从开头开始计算的连续字母数,但是这样虽看起来挺好的,都储存了各自的next数组量
//但是不好用,在查询的时候没有结束标志,整体来说这样的话操作 相对容易
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
char str[1000];
cin>>str;
int next[1000];
int len=strlen(str);//模式字符串长度。
next[0]=0;
int i;
for(i=1; i<len; i++)
{
int k=next[i-1];//k是记录的当前字母的前一个
while( str[i] != str[k] && k!=0)//如果没有找到相同的且不是到next[]为零或者是第一个(即为第一个数)
k=next[k-1]; //继续递归
if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
next[i]=k+1;
else
next[i]=0; //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
}
for(i=0; i<len; i++)
cout<<str[i]<<" ";
cout<<endl;
for(i=0; i<len; i++)
cout<<next[i]<<" ";
return 0;
}
<img src="https://img-blog.csdn.net/20140912193849256?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDY2NTAxMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
以上的是这种方式不好找结束条件,不是很好,下面的稍作修改就有了...
使用较为低级的方法求next数组的方法匹配
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int maxsize=100;
void getnext(string str,int next[])
{
int len=str.length();//模式字符串长度。
next[0]=-1;
next[1]=0;
int i;
for(i=1; i<len; i++)
{
int k=next[i-1];
while( str[i] != str[k] && k!=0 && k!=-1 )//如果没有找到相同的且不是到next[]为零或者是第一个(即为第一个数)
k=next[k-1]; //继续递归
if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
//这个地方如果k是-1的时候不会报错,并且也正好不满足这个条件,所以这样就会运行处正确的结果
next[i+1]=k+1;
else
next[i+1]=0; //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
}
}
void kmpindex(string s,string t)
{
int next[maxsize],i=0,j=0;
memset(next,-1,sizeof(next));
getnext(t,next);
j=0;
/* while(j<t.length())
{
cout<<t[j]<<" ";
j++;
}
j=1;
cout<<endl;
while(j<t.length())
{
cout<<next[j]<<" ";
j++;
} */
int m=1;
j=0;
while( i<s.length() && j<int(t.length()) )//s为原串(主串 目标串),t为匹配串(模式串)
{
if( j==-1 || s[i] == t[j] )
i++,j++;
else
j=next[j],m++;//返回的时候在增加一趟
// 其实,为什么没有用到next[]最后一个,这是因为在每一次用到的是上一个字母的位置,至于最后一个是没有用到的
}
// cout<<endl<<"*******************************************"<<endl;
if(j=int(t.length() )) //说明匹配串已经遍历完毕了,也就是说匹配成功了
cout<<m<<' '<<i-t.length()+1<<endl; //匹配成功时第一个字母的位置
else
cout<<0<<endl;
// cout<<"*******************************************"<<endl;
}
int main()
{
string a,b;
cin>>a>>b;
kmpindex(a,b);
return 0;
}
/*一直不太清楚为什么在next数组中没有左最后一个的值,其实原因很简单,就是用不到
因为在匹配时是从该字母的上一个的*/
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int maxsize=100;
void getnext(string t,int next[])
{
int j,k;
j=0; k=-1;
next[0]=-1;
while(j<t.length())
{
if(k==-1 ||t[j]==t[k])
{
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
// cout<<"j"<<" "<<j<<endl;
}
void kmpindex(string s,string t)
{
int next[maxsize],i=0,j=0;
memset(next,-1,sizeof(next));
getnext(t,next);
j=0;
cout<<' ';
/* while(j<t.length())
{
cout<<t[j]<<" ";
j++;
}
j=0;
cout<<endl;
while(j<t.length())
{
cout<<next[j]<<" ";
j++;
}*/
int m=1;
j=0;
while( i<s.length() && j<int(t.length()) )
{
if( j==-1 || s[i] == t[j] )
i++,j++;
else
j=next[j],m++;//返回的时候在增加一趟
//注意第一个next是-1,其他的都像后推
}
//cout<<endl<<"*******************************************"<<endl;
if(j>=int(t.length() ))
cout<<m<<' '<<(i-t.length())+1<<endl;
else
cout<<0<<endl;
// cout<<"*******************************************"<<endl;
}
int main()
{
string a,b;
cin>>a>>b;
kmpindex(a,b);
return 0;
}