KMP算法及修正

BF算法思路直观简明,担当匹配失败时,主串的指针i 总数回溯到i-j+2位置,模式串的指针总是恢复到首字符位置j = 1;因此,算法时间复杂度高,下面介绍另一种改进的模式匹配算法。

KMP算法可以在O(n + m)的时间数量级上完成串的模式匹配。
下面是匹配过程。
在这里插入图片描述
从上图可得,匹配仅需要从模式中第k个字符与主串中的第 i 个字符开始,依次向后进行比较。若令next[j] = k,则next[j]表明当模式中第j个字符与主串中相应字符"失配"时,在模式中需要重新和主串中该字符进行比较的字符位置,由此可引出模式串的next函数的定义:
在这里插入图片描述
模式串的next[函数]:

匹配过程中,如果i = j,各增1,否则i不变,j退回到next[j]位置再比较,重复上述步骤i,以此类推,直至下列两种可能:一种是j退到某个next值时字符比较相等,则指针各自增1,继续进行匹配;另一种是j退到值为零,则此时需要将模式继续向右滑动一个位置,即从主串的下一个字符起和模式重新匹配。

在这里插入图片描述
KMP算法形式上和BF算法极为相似,不同之处仅在于:当匹配过程中产生"失配"时,指针i不变,指针j退回到next[j]所指示位置上重新进行比较,并且当指针j退至0时,指针i和指针j需要同时增1,即若主串的第i个字符和模式的第1个字符不等,应从主串的第i+1个字符起重新匹配

KMP算法:

int Index_KMP(SString S,SString T,int pos)
{
   i=pos;j=1;
   while(i<=S.length && j<=T.length)   //两串均未比较到串尾 
   {
      if(j==0 || S.ch[i]==T.ch[j])//继续比较后续字符
        {
			i++; 
			j++;
		}                      
      else
        j=next[j];                      //模式串向右移动
    }
   if(j>T.length)  return i-T.length;   //匹配成功
   else  return 0;                      //匹配失败
}

要实现KMP算法,我们还需要计算next函数值,令next[1] = 0:
.

void get_next(SString T, int next[])
{//求模式串T的next函数值并存入数组next 
   i = 1; next[1] = 0; j = 0;
   while(i < T.length)
   {
       if(j == 0 || T.ch[i] == T.ch[j])
        {
        	i++,j++,next[i] = j;
		}
       else
         j = next[j];
   }
} 
  • 算法时间复杂度为O(m),通常,模式串的长度m比主串的长度n要小的多,因此,对整个匹配算法来说,所增加的这点时间是值得的。
  • 但前面定义next函数在某些情况下有缺陷,我们可以进行改进,例如模式”aaaab“在和主串”aaabaaaab“匹配时,当 i =4、j =4 时S.ch[4] ≠ T.ch[4],由 next[j]的指示还需要进行i=4、j=3,i=4、j=2,i=4、j=1这3次比较。实际上,因为模式中1~3个字符和第4个字符都相等,因此不需要再和主串的第4个字符相比,可以将模式连续向右滑动4个字符的位置直接进行i=5、j=1的字符比较。直接将前面的所有next值更改为0,当前next值作为nextval[j]的值

计算next函数修正值

void get_nextval(SString T, int nextval[])
{
	//求模式串T的next函数修正值并存入数组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])
				nextval[i] = j;
			else
				nextval[i] = nextval[j];
		}
		else h = nextval[j];
	}
}

未修正代码实现:

#include<iostream>
#include<string>
using namespace std;
int next[105];

int Index_KMP(string S,string T,int pos) 
{
	int i = pos;
	int j = 1;
   while(i <= S.size()&& j <= T.size())   //两串均未比较到串尾 
   {
      if(j == 0 || S[i] == T[j])//继续比较后续字符
        {
			i++; 
			j++;
		}                      
      else
        j = next[j];                      //模式串向右移动
    }
   if(j > T.size())
    	return i-T.size();   //匹配成功
   else 
   		return 0;                      //匹配失败
}
void get_next(string T, int next[])
{//求模式串T的next函数值并存入数组next 
   int i = 1; 
   next[1] = 0;
   int j = 0;
   while(i < T.size())
   {
       if(j == 0 || T[i] == T[j])
        {
        	i++,j++,next[i] = j;
		}
       else
         j = next[j];
   }
} 
int main()
{
	string S, T;
	cout<<"输入S:";
	cin>>S;
	cout<<"输入T:";
	cin>>T;
	get_next(T,next);
	cout<<Index_KMP(S,T,1);
	return 0;
}

在这里插入图片描述
修正代码实现:

#include<iostream>
#include<string>
using namespace std;
int next[105];

int Index_KMP(string S,string T,int pos) 
{
	int i = pos;
	int j = 1;
   while(i <= S.size()&& j <= T.size())   //两串均未比较到串尾 
   {
      if(j == 0 || S[i] == T[j])//继续比较后续字符
        {
			i++; 
			j++;
		}                      
      else
        j = next[j];                      //模式串向右移动
    }
   if(j > T.size())
    	return i-T.size();   //匹配成功
   else 
   		return 0;                      //匹配失败
}

void get_nextval(string T, int nextval[])
{
	//求模式串T的next函数修正值并存入数组nextval
	int i = 1,j = 0;nextval[1] = 0;
	while(i < T.size())
	{
		if(j == 0 || T[i] == T[j])
		{
			i++;
			j++;
			if(T[i] != T[j])
				nextval[i] = j;
			else
				nextval[i] = nextval[j];
		}
		else j = nextval[j];
	}
}
int main()
{
	string S, T;
	cout<<"输入S:";
	cin>>S;
	cout<<"输入T:";
	cin>>T;
	get_nextval(T,next);
	cout<<Index_KMP(S,T,1);
	return 0;
}

在这里插入图片描述


内容参考:《数据结构》 严蔚敏

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值