KMP匹配算法的改进及代码

KMP匹配算法的改进及代码实现(nextval)
在这里插入图片描述

这里写目录标题

前提

此文已假设你懂得了KMP的原理和next数组的求法,此处我对nextval(KMP改进)数组的原理进行介绍。
若没有相应基础的同学可以查看下方链接,先学习KMP基本原理,以及next数组的原理和代码实现。
1.KMP算法图解
2.为什么KMP算法不会跳过(漏掉)正确的答案
3.KMP算法之求next数组代码讲解
4.KMP算法之NEXT数组代码原理分析
看完上面的博客和视频,应该就能懂的KMP原理以及next数组的代码实现了(毕竟我就是这么过来的 T.T)。

KMP由于不用主串下标i的回溯,其时间复杂度由暴力匹配的O(m*n)改进到了O(m+n),每次失配,i呆在原地,j回溯到next[j]的位置就可以重新进行匹配了,十分方便。
但是,后面有人发现,KMP算法还是有缺陷——j回溯的还不够快。因为一旦发现失配重新进行匹配时,j回溯的越多,匹配的就越快。例如,当主串S=“aaaabcde”,子串T=“aaaaax”,其next数组为012345。
在i=5,j=5时发生失配如下图①;于是j=next[5]=4,重新匹配如下图②;依然发现‘b’与子串4位置上的‘a’不相等,于是再重新匹配,j=next[4]=3,如下图③,这样依次类推是④⑤。直到j=next[1]=0时,根据next代码,此时i++,j++。得到i=6,j=1如下图⑥。
图源:《大话数据结构》
按照next数组进行回溯的方法,上面的②③④⑤其实是多余的判断,这是因为在T[5]失配,而T[5]又与前四位相等,既然S[5]!=T[5],那必然不会等于T[1]、T[2]、T[3]和T[4],之后的四次重新匹配也肯定是徒劳无功。
于是要重新设置一个新数组nextval(默认nextval[1]=0,nextval[2]=1)能够使j跳过一些无意义的回溯,而快速回溯到能够正确开始匹配的位置。

思路

假设此时在i处已经发生失配,j回溯到了next[j]的位置。
在这里插入图片描述

  1. 如果 T[i] != T[j] ,因为S[i]已经不等于T[i]了,那么S[i] 就可能会等于T[j],于是nextval[i]=j;(此时nextval数组和next数组的值是一样的)
    在这里插入图片描述

  2. 如果T[j] == T[i],那么失配的S[i]必不会等于T[j]
    在这里插入图片描述
    于是我们就继续往前找前缀 j=next[j](如果不知道为什么找的是前缀可以查看KMP算法之求next数组代码讲解14分11秒),如果T[j]==T[i],就继续找(不然匹配始终会在主串i处终止,因为S[i]必不会等于T[j]),直到T[i] != T[j]或者 j ==0为止
    此时的nextval[i]=j,如果上述步骤使用循环语句,事实上也有nextval[i]=nextval[next[i]]。在这里插入图片描述
    手算nextval数组见数据结构 KMP改进算法 nextval数组求值

代码

//nextval数组

void get_nextval(char T[], int nextval[])
{
	int i = 1;//后缀
	int j = 0;//前缀
	nextval[1] = 0;
	while (i < T[0])
	{
		if (j == 0 || T[i] == T[j])
		{
			i++, j++;
			if (T[i] == T[j])//多了判断
			{
				nextval[i] = nextval[j];
			}
			else
			{
				nextval[i] = j;
			}
		}
		else
		{
			j = nextval[j];//继续往前找前缀
		}
	}
}

//next数组 作为参照不同处

void get_next(char T[], int next[])
{
	int i=1;//后缀的最后一位的下标
	int j = 0;//前缀的最后一位下标
	next[1] = 0;//规定next[1]=0
	while (i < T[0])//T[0]等于T串的长度,循环遍历T串,得到next表
	{
		if (j == 0 || T[i] == T[j])//如果前缀和后缀相等,找到一位next[i]
		{
			i++, j++;
			next[i] = j;
		}
		else
		{
			j = next[j];
		}
	}
}

利用下面例子做一回实验
在这里插入图片描述
串第一位存放整个字符串的长度。分别使用next和nextval数组,每次回溯就计数一次
使用next数组:
在这里插入图片描述

使用nextval数组:
在这里插入图片描述

青山不改 绿水长流
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值