应付考试用的KMP算法中next数组及nextval数组的计算(笑)

来源:互联网 发布:淘宝直通车关键词价格 编辑:程序博客网 时间:2024/05/16 04:01

随着数据结构考试的紧邻,突击复习又成为学生们的首要目标(笑)

做到“串”课后习题的时候,突然发现我还没有掌握KMP算法!!!

于是就在网上狂找资料,同时结合课本,算法思想是明白了,但要命的是这next数组、nextval数组真心不好求,我就在想怎样才能将求数组的方法搞的浅显易懂一些,现将方法分享如下:

对了,本篇文章五成以上算是转载内容。

在介绍计算方法之前,请各位看官移步:阮一峰老师的讲解

阮老师从侧面说明了KMP算法的实现过程。

首先我要整理一下我所了解的KMP(干货还是有的):(如您没有时间请直接跳到第三大段找计算方法)


我把一个公式放在前面“模式串要移动的长度=已进行成功匹配的模式串字符长度(j)-对应的模式串的部分匹配值”(未详讲,请参看阮一峰老师的博客)

那么什么是“模式串的部分匹配值”呢?

我们在这里定义两个概念:“前缀”、“后缀”

例如:对于给定的模式串1.aba,其前缀为{a}、{ab},其后缀为{ba}、{a};2.a,其前缀为空,后缀也为空。

即:前缀为一个字符串除掉最后一个字符后剩余字符的顺序排列、后缀则为除掉第一个字符后剩余字符的顺序排列。

在了解前缀、后缀之后,我们给出“部分匹配值”的定义。

定义:一个字符串的部分匹配值为该字符串前缀、后缀中相同部分的字符(最大)数目。

下面验证该定义的合理性(偏离主题了,就不验证了)。


不是看不懂书上(数据结构C语言版)关于next数组的定义吗?接下来我用上述给出的定义将next数组进行解释。

书上的定义如下:


1.当j=1时,next[1]=0这个应该很好理解吧,模式串的第一个字符就不匹配,当然是从头开始比较下去了(为什么为0请看KMP算法的实体);

2.来看第二个1<k<j,并且“t1t2……t(k-1)”=“t(j-k+1)t(j-k+2)……t(j-1)”

这是什么意思呢?我们回首一下刚才给出的“前缀”“后缀”,是不是就能得到“前缀”与“后缀”相同的(最大数目)(正是部分匹配值)=k-1

k=next[j]=部分匹配值+1

这样,我们就得到了next数组的计算方法了(涵盖了第三种情况)

下面我们来验证一下:

以书上给出的模式串为例:abaabcac

12345678abaabcac01122312

next[1]=0;

next[2]=部分匹配值+1=“a”的“前缀”与“后缀”相同的最大数目+1=0+1=1;

……

next[6]=部分匹配值+1=“abaab”的“前缀”与“后缀”相同的最大数目+1=2+1=3;

……

完全正确!

next数组计算出来了,那么nextval数组是怎么得到的呢(无关算法)?

以aaaab为例,按我们上述给出的计算方法,求得其next数组为:

12345aaaab01234

而我们在实际匹配过程中,发现(书上讲的我不想看= =)

如果在aaaab的第二个位置失配,说明主串的失配位置一定不是“a”,那么根本不需要同模式串的第一个字符“a”进行比较,但next[2]=1,这样跟我们的预期不符,nextval数组就是基于这种情况下被提出的。

nextval数组的计算方法为:

公式:若t[j]=t[next[j]],则nextval[j]=nextval[next[j]],否则保持不变;

人话:先算出模式串的next数组,依次从第二个开始向后更新,如果依照next数组指向的字符与所求字符是相同的话(想一想上述给出的例子“aaaab”),就将所求字符的next值更新为本来该字符next数组指向的字符的next值;如果不相同,则保持不变。

仍以aaaab为例:

12345aaaab01234000
04

nextval[1]=0;

nextval[2]=0;因为t[1]=“a”,t[2]=“a”,这两个字符相同,所以更新为0;

……

nextval[4]=0;因为t[4]=“a”,t[3]=“a”,字符相同,所以更新为0(当然是先求nextval[3]了笨蛋);

nextval[5]=4;因为t[5]=“b”,t[4]=“a”,字符不相同,所以保持不变仍然为4;

怎么样,是不是很简单。


当然,我所讲的并没有触及到核心内容:“部分匹配值”提出的原因,next、nextval数组的函数实现。如果通过阅读本文能给你带来收获,如此甚好。









阅读全文
0 0