数据结构·KMP·笔记

KMP

1.简介

KMP算法目的是在主串中快速找到一个字串
快速:并非一位一位比较后发现不匹配然后后移一位
字串:此处我们以后叫模式串

2.KMP使用的例子

红色框住是完全匹配部分,蓝色是最大公共前后缀
当字符发生不匹配时(红色框外第一对,主串B!=模式串A)开始在完全匹配部分找最大公共前后缀
红色框住是完全匹配部分,蓝色是最大公共前后缀下一步,将前缀移动到后缀,然后在下一个发生不匹配的字符位置之前完全匹配部分找最大公共前后缀
当模式串长度超出主串时,匹配失败
在这里插入图片描述
另一个成功案例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运用KMP算法查找字串在效率上有了极大的提升

3.公共前后缀是什么?怎么找?

公共前后缀:
模式串中完全匹配部分 相同的地方
其特点是 前缀从前往后数 后缀从后往前数
例如ABCD 前缀是A AB ABC ABCD而后缀是D CD BCD ABCD

最大公共前后缀:
顾名思义,最大公共前后缀就是公共前后缀中最大的一串。
公共前后缀应该在比较指针(主串和模式串不一样的字符)左边开始找

4.next数组

既然我们知道了KMP算法,那么如果我们要用代码实现,我们还需要知道next数组,next数组的意思就是下一步应该如何做,我们应该怎么对模式串进行移动
在这里插入图片描述
一些名词解释:
1号位,2号位:指的是完全匹配部分的第一个,第二个
当前位置:指的是比较指针的位置就是匹配发现字符不相同的(首个)位置

规律:当最大公共前缀为n时,n+1号位与主串当前位进行比较

ps:这里一般从下标1开始记录

此时所得的next数组的值就是对应几号位的值了
比如这里

下标    0   1 2 3 4 5 6 7 8 9 10 11 12
next  不计  0 1 1 2 3 4 2 2 3 4  5  6

如果我们可以由前几位的next数组值得到下一位的next的值,通过这种递推的方式我们可以得到求next数组的代码

假设我们已知next[j]=t
分析:
在这里插入图片描述

代码:

void getNext(Str substr,int next[])
{
	int j=1,t=0;
	next[1]=0;
	while(j<substr.length)
	{
		if(t==0||substr.ch[j]==substr[t])
		{	
			next[j+1]=t+1;
			++t;
			++j;
		}else t=next[t];
	}
}

5.nextval数组

若出现特殊情况,我们可以对KMP算法进行优化
在这里插入图片描述
递推关系分析:
在这里插入图片描述

j=1,nextvval=0
j>1 Pj!=Pnext[j],nextval[j]=next[j]
Pj=Pnext[j],nextval[j]=nextval[next[j]]
代码:

void getNextval(Str substr,int nextval[])
{
	int j=1,t=0;
	nextval[1]=0;
	while(j<substr.length)
	{
		if(t==0||substr.ch[j]==substr.ch[t])
		{
			if(substr.ch[j+1]!=substr.ch[t+1])
				nextval[j+1]=t+1;
			else 
				nextval[j+1]=nextval[t+1];
			++t;++j;
		}else	t=nextval[t];
	}
}
			

6.KMP算法的实操

next数组

void getNext(Str substr,int next[])
{
	int j=1,t=0;
	next[1]=0;
	while(j<substr.length)
	{
		if(t==0||substr.ch[j]==substr[t])
		{	
			next[j+1]=t+1;
			++t;
			++j;
		}else t=next[t];
	}
}
int KMP(Str str,Str substr,int next[])
{
	int i=1;j=1;
	while(j<str.length &&j<=substr.length)
	{
		if(j==0||str.ch[i}==substr.ch[j])
		{++i;++j;}
		else {j=next[j];}
	}
	if(j>substr.length)
		return i-substr.length;
	else
		return 0;
}

nextval数组:

void getNextval(Str substr,int nextval[])
{
	int j=1,t=0;
	nextval[1]=0;
	while(j<substr.length)
	{
		if(t==0||substr.ch[j]==substr.ch[t])
		{
			if(substr.ch[j+1]!=substr.ch[t+1])
				nextval[j+1]=t+1;
			else 
				nextval[j+1]=nextval[t+1];
			++t;++j;
		}else	t=nextval[t];
	}
}
int KMP(Str str,Str substr,int nextval[])
{
	int i=1;j=1;
	while(j<str.length &&j<=substr.length)
	{
		if(j==0||str.ch[i}==substr.ch[j])
		{++i;++j;}
		else {j=nextval[j];}
	}
	if(j>substr.length)
		return i-substr.length;
	else
		return 0;
}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值