再谈KMP/BM算法(II)

本文探讨了KMP算法中next[i]与Zi(S)的关系,提出根据Z值表填充next[i]表的规则,并详细解释了如何用Z值表构造BM算法的goodsuffix[i]表,包括计算模式串逆串Sr的Z值、未修正的好后缀跳转表以及修正跳转步数的过程。
摘要由CSDN通过智能技术生成

KMP算法中next[i]与Zi(S)的对应关系

我在《KMP算法详解》一文中已经介绍了next[i]的含义,对于S[i],next[i]的意义是,如果存在k使得S[1...i-k]=S[k...i-1]且S[i-k+1]!=S[i],那么next[i]=i-k+1。实际上对于满足条件的k,其Z值Zk(S)就满足k+Zk(S)=i,next[i]=Zk(S)+1,所以我们可以用如下方法根据模式串S的Zi(S)表填写对应的next[i]表。

规则一,从头到尾遍历Zi(S),当遍历到元素k时,如果Zk(S)!=0,那么next[k+Zk(S)]=Zk(S)+1,如果还存在k'使得k+Zk(S)=k'+Zk'(S)那么next[k+Zk(S)]等于Zk(S)+1与Zk'(S)+1的较大者。

规则二,对于遍历Zi(S)列表之后,尚未填写的元素的next值,我们按照如下原则填充,对于元素S[i],如果S[i]=S[1],则其next值next[i]=0,否则next[i]=1。

根据上面的原则,我们对于《KMP算法详解》中的老例子通过Zi(S)构建next[i]的表格如下。这里对于S[8],由于4+Z4(S)=8,7+Z7(S)=8,所以我们选择其中的较大者Z4(S)=4,令next[8]=Z4(S)+1=5。对于S[9],由于9+Z9(S)超出了pattern数组的范围,所以我们不使用该Z值计算next跳转表。实际对于下表,除了next[8]之外,其余均是由规则二填写。相较于KMP三人给出的next表填写算法,利用Z值表填写next表固然增加了一个转换层,降低了算法效率,但是从易理解的角度讲,由Z值到next值的转换是十分有意义的。

  1 2 3 4 5 6 7 8 910
patternabcabcacab
Zi(S)0004001020
next0110110501

BM算法goodsuffix[i]与Zi(S)的对应关系

用Z值表填写goodsuffix表的过程,要比填写next表复杂得多。首先,BM算法使用的是后缀自包含而Z值计算的是前缀,另一方面我们还需要找到最长的与后缀相匹配的前缀的长度,来修正跳转值。这里我们分别来处理这两个问题。

对于BM算法中的模式串S,我们可以计算其逆串Sr的Z值,Zi(Sr)。例如,对于S="abcxxxabc",Sr="cbaxxxcba",我们可以得到Sr的Z值表如下图所示

  1 2 3 4 5 6 7 8 9
Srcbaxxxcba
Zi(Sr)000000300
我们可以用如下方法计算出模式串S的最大包含后缀表rpr(i)。遍历Sr的所有Z值,对于满足n-i-Zi(Sr)+1>0的i,令rpr(n-i-Zi(Sr)+1)=Zi(Sr),对遍历之后未被填充rpr(i)值的元素,赋值0(如果S从索引0开始,则公式要改动为n-i-Zi(Sr))。 如下图,这里要注意,对于i=7,Z7(Sr)=3,但是9-7-3+1<=0,所以我们放弃这个值。
  1 2 3 4 5 6 7 8 9
Sabcxxxabc
rpr(i)000000000

之后,我们可以计算出未修正的好后缀跳转表。对于rpr(i)=0的元素,goodsuffix'[i]=patlen+n-i,对于rpr(i)!=0的元素,goodsuffix'[i]=n-rpr(i),其中n是模式串最末元素的索引值。如果模式串的首字符从0开始的话,n!=patlen这里要特别注意。

  1 2 3 4 5 6 7 8 9
Sabcxxxabc
goodsuffix'17161514131211101

另外,我们还需要找到与后缀匹配的最长前缀p,用于修正goodsuffix'的跳转步数。p值在构建Zi(Sr)的时候可以得到,对于Sr中的元素Sr[i],如果有i+Zi(Sr)-1=n,那么p=Zi(Sr),如果有多个i满足该条件,则p等于其中的最大者。上例中对于Sr="cbaxxxcba",我们有7+Z7(Sr)-1=9,所以p=Z7(Sr)=3。在修正goodsuffix'的跳转步数时,我们对于n-i>=p的元素goodsuffix'值统一减去p即可得到最终的goodsuffix值。如下图

  1 2 3 4 5 6 7 8 9
Sabcxxxabc
goodsuffix1413121110911101

上面虽然列出了4个步骤,但是在实际计算BM的好后缀跳转表的过程中,除了Zi(Sr)需要单独计算之外,其余三个步骤,可以一次完成。

在使用Z值表计算KMP算法或者是BM算法的跳转表的过程中,模式串起始索引要特别注意,如果S[0...n]从0开始,则要对一些地方做修正。因为如果模式串从索引0的位置开始,其最末元素n!=patlen,所以在计算过程中,哪里用的是模式串的长度,哪里用的是模式串最末元素的索引,要格外留心。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值