KMP

  最近学到了KMP这章,今天又重新温习了一遍,下面对kmp算法进行一下总结.

传统的字符串匹配,时间复杂度为O(m*n),m,n分别为主串s和匹配串p的长度,每次进行匹配时,当发现失配时,主串要发生回溯.

KMP:

  kmp采用了一个辅助数组nextval,利用匹配串自身的特点,当i与j失配时,i不发生回溯,j后退.,与p的第k个字符匹配判断(k<j).

  有下列等式

  1. p1p2p3..p(k-1)=S(i-k+1)S(i-k+2)....Si-1

 2.  p(j-k+1)p(j-k+2)......p(j-1)=S(i-k+1)S(i-k+2)....Si-1

由1.2知

 p字符串有这个性质:

   p1p2p3....p(k-1)=p(j-k+1)p(j-k+2)....p(j-1).当尾下标为j-1时,j发生失配

  即前k-1字符与后k-1字符相同.

nextval数组:

  可以用迭代的思想来求nextval数组中的值.

例模式p: a b a b a c b

显然nextval[1]=0,nextval[2]=0,nextval[3]=1,nextval[4]=2,nextval[5]=3,nextval[6]=0,nextval[7]=0.

 怎样进行迭代呢,求nextval[4]时,因为p[2]=p[4],而在p[3]中p[1]=p[3].所以p[4]=p[3]+1.

 而求nextval[6]呢? 显然nextval[6]不是nextval[5]+1而来的,因为p[3]!=p[6].但是我们可以回代,

 即nextval[6]是不是等于nextval[nextval[5]]+1的值,为什么可以这样呢,因为nextval[5]=k,可以知道

前k个与后k个相同,此时我们仅需判断在加一位是否相同,如果相同则加1,否则继续推,直至为0.此时nextval[6]也为0.

代码:由于我采用的是下标为0开始,所以p的首位为Po:

//kmp算法
#include <iostream>
#include <cstring>
using namespace std;
#define NUM 1000000
char s[NUM],p[NUM];
int nextval[NUM]={-1};
void GetNext(int m)      //获取next数组的值
{
	int i=0,j=-1;
	for(i=1;i<m;++i)
	{
		while (j!=-1&&p[j+1]!=p[i])  //迭代过程
		{
			j=nextval[j];
		}
	 if(p[j+1]==p[i]) j=j+1;  //如果迭代成功,则原先基础加 1
	 nextval[i]=j;  //赋值,否则为-1
	}
}

bool KMP(int n,int m)
{
	int i,j=-1;
	for(i=0;i<n;++i)
	{
		while (j!=-1&&s[i]!=p[j+1]) 
		{
			j=nextval[j];     //失配时,从nextval[j]开始匹配
		}
		if(p[j+1]==s[i]) ++j;
		if(j==m-1) { cout<<"匹配成功!,出现的首位是第"<<i-m+2<<"位"<<endl;return true;}
	}
	return false;
}
int main()
{
	int test,n,m;
	cout<<"请输入测试组数"<<endl;
	cin>>test;
	while (test--)
	{
	 memset(s,0,sizeof(s));
	 memset(p,0,sizeof(p));
	 memset(nextval,-1,sizeof(nextval));
	 cout<<"请输入主串字符"<<endl;
	 cin>>s;
	 n=strlen(s);
	 cout<<"请输入模式串字符"<<endl;
	 cin>>p;
	 m=strlen(p);
	 GetNext(m);
	 if(!KMP(n,m))
	 cout<<"没有匹配的字符"<<endl;
	}
	system("pause");
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值