KMP算法之我见(NEXT数组的递归解析)

来源:互联网 发布:数据库无法登陆 编辑:程序博客网 时间:2024/05/16 16:13

通过根据next[j]求解next[j+1]的详细过程解析next数组的快速求法

一、已知条件:next[j] = k,匹配图如下:

设当前失配点为Pj,则下一次在该位置与主串比较的字符是Pk。且可知信息:

 

二、求next[j+1]。即若当前失配点为Pj+1,求下一次该移动到此位置与主串比较的字符序列。

通过next数组的含义可知,next[j+1]等于串P0P1…Pj-1Pj的最长相等缀子串对的长度。(注:笔者自定义缀子串对为等长度的前缀子串和后缀子串)

1、暂且用枚举的方法列出串P0P1…Pj-1Pj的所有缀子串对,则可对比求出最长的是哪一对缀子串对,且next[j+1] 等于其长度加1。过程如下:

前缀子串(第一个字符不变) 后缀子串(最后一个字符不变)

这些所有的子串对中哪一对是最长相等的呢?

7可见红线框内的式子正好等于前文的2式,且已知2式不等,可推出式7不等。依次推至最后一个缀子串对式8,对应前文的式4,则式4不等可推出式8不等。

此时观察式6,可见红线框内的式子正好对应前文式1,且式1相等,则此时有:

若 Pk = Pj,则式6相等,且该缀子串对为最长相等子串对,则有:

Next[j+1] = k+1 = next[j] + 1          Pk = Pj)

(此处可得出结论,next[j+1]最大值为next[j] + 1

 

2、若Pk != Pj,则问题转变为上列缀子串对中式5及之前的所有缀子串对哪一对才是最长相等的。

此时可看成另一个匹配问题,主串、模式串都为前文匹配中模式串的子串。

匹配图如下:

此次新的匹配主串为Pj-kPj-k+1…Pj-1Pj,模式串为P0P1…Pk-1 Pk,且在Pk处失配。

那下一个该处于Pk位取代其与Pj相比的字符是什么呢?利用next[k]可得。

设 h = next[k],则下一次匹配时Pj对应Ph。且根据next数组含义知:

P0P1…Ph-1   =   Pj-h…Pj-1     (该式即上表第三行信息,长度strlen=h

若此时Ph = Pj,则P0P1…Ph-1Ph   =   Pj-h…Pj-1Pj ,则此时为Ph+1对应Pj+1。

则有:

next[j+1] = h+1=next[k]+1=next[next[j]]+1 (Pk != Pj且Ph = Pj)

3、若此时Ph != Pj,,则缀子串对P0P1…Ph-1 Ph 和Pj-h…Pj-1 Pj不相等。

此时该缀子串对作用地位等同于前文式6式,重复式6的的下一步工作,依次循环,直到解决最初问题:最长的相等缀子串对(前文第一次匹配问题)。此处循环体现了next数组中的递归思想。

 

以上过程实现代码如下:

 

上列代码中设置了一个next[0]的值,而执行循环体每一次的执行是利用已知的next[i]值和P[i]P[k]next[i+1]的值。

 

三、next数组的优化

引用前文(二、2)的表格加多一列:

设此时Pj=Pnext[k],即Pj=Ph,故Pj+1应对应Ph+1,即next[j+1] = h+1

此时若多做一步判断,Pj+1 ?Ph+1(判断是否相等)

   1、若Pj+1 !=  Ph+1则next[j+1] = h+1  (与前文结论一致不变)

   2、若Pj+1 = Ph+1,则上表形成的新的匹配在主串为Pj+1处不失配,也即模式串在Ph+1处不失配,那无法求出next[j+1],故要让模式串前进,在Ph+1处失配。也就是说虽然Pj+1 = Ph+1,但应该让模式串前进找到一个与Pj+1对应且会在该处失配的字符元素,此时此字符元素就是next[j+1]指向的位置元素。该过程简化了next数组。

² 注:此处千万别想成Pj+1 = Ph+1,那下一步匹配Pj+2 和 Ph+2,清楚当前阶段目的不是要匹配,而是求next[j+1],故必须让Pj+1 为失配点。

 

上述优化实现代码如下:


 

 

笔者对上段代码中最后的 if else 语句有些疑问,因为它只将前文(三、2)的情况执行了一遍,而不是循环。故认为可以改成下列语句

 

上述代码只是假设,未作测试。算是留下一个小问题,留下遗憾暂时结束KMP算法的学习。

0 0
原创粉丝点击