/*
*通过计算返回子串的next数组
*/
void Get_Next(string s,int *next)
{
int i,j,len;
i=1;
j=0;
len=s.length();//此处str.length()表示串长度
next[0] =0;
while(i<len)
{
if (j==0 || s[i-1]==s[j-1])//s[j-1]表示前缀的单个字符,s[i-1]表示后缀的单个字符
{
++j;
++i;
next[i-1] =j;
}
else
j=next[j-1 ]; //若字符不相同,则j回溯*/
}
}
/*
*优化改进后的next函数
*通过计算返回子串的next数组
*/
void Get_NextVal(string s,int *next)
{
int i,j,len;
i=1;
j=0;
len=s.length();//此处str.length()表示串长度
next[0] =0;
while(i<len)
{
if (j==0 || s[i-1]==s[j-1])//s[j-1]表示前缀的单个字符,s[i-1]表示后缀的单个字符
{
++j;
++i;
if (s[i-1]!=s[j-1])/*若当前字符与前缀字符不同*/
next[i-1] =j; /*则当前的j为next在i位置的值*/
else
next[i-1] =next[j-1];/*与前缀字符相同*/
/*字符的next值赋值给next在i-1位置的值*/
}
else
j=next[j-1 ]; //若字符不相同,则i回溯*/
}
}
测试函数
void main(void)
{
string t;
t="ababaaaba";//测试字符串
int len;
len=t.length();
int *p=new int[len];
Get_Next(t,p);//测试Get_Next函数
cout<<"Get_Next函数得到next数组值:";
for (int i=0;i< len;i++)
cout<<p[i];
cout<<endl;
Get_NextVal(t,p);//测试Get_NextVal函数
cout<<"Get_NextVal函数得到next数组值:";
for (int i=0;i< len;i++)
cout<<p[i];
cout<<endl;
delete [] p;
system("pause");
}
输出结果
/*
* 返回子串t在主串s位置,若不存在返回-1
* t非空,
*/
int Index_KMP(string s,string t, int pos)
{
int i=pos;//i用于主串s当前位置下标0~s.length()-1
int j=0;//j用于子串t当前位置下标从0开始
int next[255];//定义一next数组
Get_NextVal(t,next);//获取子串t的next数组
int sLen=s.length();//主串长度
int tLen=t.length();//子串长度
while(i<=sLen && j<=tLen)
{
if (j==0 || s[i-1]==t[j-1])//字母相等继续
{
++i;
++j;
}
else
{
j=next[j-1];//j退回适合位置i不变
}
}
if (j>tLen)
return i-tLen-1;
return -1;
}
测试函数
void main(void)
{
string s,t1,t2;
s="aaaabcde";
t1="aaaaax";
t2="de";
int x=Index_KMP( s, t1, 0);//索引位置从0开始
if (x==-1)
cout<<"t1不在s中"<<endl;
else
cout<<"t1在s中位置是"<<x<<endl;
x=Index_KMP( s, t2, 0);
if (x==-1)
cout<<"t2不在s中"<<endl;
else
cout<<"t2在s中位置是"<<x<<endl;
system("pause");
}
输出结果
参考文献:
《 大话数据结构 》--程 杰 下载地址:大话数据结构