KMP算法

	个人柑橘KMP算法并不难,但是理解起来确实麻烦。稍微记一下,免得日后遗忘。

	KMP算法优于BF算法就在于引入了next数组从而使子串与目标串的同步速度加快从而
	优化了时间。
	
	next数组是个人感觉最难理解的地方,也是用了一段时间才搞懂,现记录一下。

next数组何用:

			next数组用来在子串与目标串的匹配中使子串更快的移动。其中next[j](下标从0
			开始)表示前j个元素中(即下标到j-1)**包含第j个元素(下标j-1)的后串和带第一
			个元素的前串相等的最长的子串的长度**(定语太多不好理解,举个例子就懂了,
			其中next[0]默认等于-1,next[1]默认
			等于0(以后解释):
								s[8]=a  b c a b c a b
							next[]=-1 0 0 0 1 2 3 4 0
							next[3]即前三个a b c中包含c的最长的前后相等的子串长度,显然没有,为0.
							next[4]即前四个a b c a中包含a的最长的前后相等的子串长度,即第一个
							       元素a(下标0)与第四个元素a(下标3)为最长的相等的子串,长度为1;
							next[6]即前6个a b c a b c中包含c的最长的前后相等的子串的长度,即前三个a b c
									和后三个a b c。
							next[7]同理,是前四个a b c a和后四个a b c a。

next数组如何求,先放上代码

int *Get_Next(Str &b)
{
	int *next=(int *)malloc(sizeof(int)*(b.length+1));
	next[0]=-1;
	int k=-1;
	int j=0;
	while(j<=b.length)
	{
		if(k==-1||b.str[k]==b.str[j])
			next[++j]=++k;
		else
			k=next[k];
	}
	return next;
}
					看一下,感觉应该不难理解,个人建议先按照上边的例子🌰,自己先跑一下整个next数组的过
				程,再看下面的解释。
					我想应该不难,除了最后的`else k=next[k]`这确实是个老大难的问题。
					放个图理解一下。

next数组

						现在假如下标为0 1 2的串已与下标为j-3 j-2 j-1的串相匹配,即next[j]=3,则下一步应该比
					较下标为3的元素与下标为j的元素,显而易见,若str[3]==str[j],则str[++j]应当赋值为++k。	
					(如果你看了前面的代码并自己摸你了一遍,现在应该知道k是什么,k即为前串最长的串的	
					下标),倘若str[3]!=str[j],这是k=next[k]又是为何呢!现在想,倘若要在前j+1个元素中
					(即下标为j+1前)寻找包含第j+1个元素(下标为j)的子串,next[j+1]结果无非是0或者非0,
					为0时即str[0]与str[j]不想等,否则子串中一定包含元素str[j],可是元素str[3]与str[j]不等,
					接下来该如何找呢!想象一下极端情况,倘若next[j+1]==1;则子串一定是str[j]与str[0]。倘
					若有第二个元素令next[j+1]==2,则一定是str[j-1]与str[0]相等,srt[j]与str[1]相等,依次类
					推。           
						可是在寻找next[j+1]之前,str[j-1]是否已经与前面的某个元素相匹配了呢?是的,那个元
				   素的下标就是k-1,可是又不能用k-1(因为str[k]与str[j]不想等),之前还有没有一个与
					str[j]相等的元素呢?答案肯定是有的。str[j-1]==str[k-1]==str[next[k]-1](想一想为什
				   么)。    str[j-1]==str[next[k]-1],同理,下标为j-2的元素也已经在之前匹配过了,依次类
				   推。    我们接下来只需要比较str[j]和和str[next[k]]是否相等即可,倘如不想等,继续令
				   k=next[k],直到找到相等的串,若找不到,则为-1。
				   		这一段比较晦涩难懂,建议静下心来慢慢读一读想一想,多去找找资料。倘若next数组解
				   决了,其余的自然不成问题。

总代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef struct list
{
	char str[101];
	int length;	
}Str;


int *Get_Next(Str &b)
{
	int *next=(int *)malloc(sizeof(int)*(b.length+1));
	next[0]=-1;
	int k=-1;
	int j=0;
	while(j<=b.length)
	{
		if(k==-1||b.str[k]==b.str[j])
			next[++j]=++k;
		else
			k=next[k];
	}
	return next;
}


void Find_Location(Str &a,Str &b,int *next)
{
	int i=0,j=0;
	while(i<a.length&&j<b.length)
	{
		if(j==-1||a.str[i]==b.str[j])
		{
			i++;
			j++;
		}
		else
			j=next[j];
	}
	if(j==b.length)
		cout<<"Find is:"<<i-j+1<<endl;
	else
		cout<<"Not Find";
	return ;
	
}


int main()
{
	Str a,b;//a 目标串 b 模式串
	cout<<"in str1:";
	cin>>a.str;
	a.length=strlen(a.str);
	
	cout<<"in str2:";
	cin>>b.str;
	b.length=strlen(b.str);
	
	int *next=Get_Next(b);
	Find_Location(a,b,next);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值