再谈AC算法

在我的《AC算法详解》一文中,还存在一个很大的疏漏,那就是用蛮力法计算自动机的fail跳转表,这实际上是一个极度低效的方法。在Aho,Corasick两人的论文中,给出的是逐层求fail表的方法,两人证明了这个方法可以在O(n)(其中n为所有模式串的总长度和)时间复杂度内计算出模式集合P的fail跳转表,下面,我就来补完这一算法的执行步骤。还是以之前的模式集合P{he,she,his,hers,era}为例来说明,其构建的goto表如下图所示。这里为了描述方便,我们将该图简记为g,令g(a,b)为图中的一个转换a代表当前状态,b代表当前状态下的一个合法输入。例如g(1,e)=2表示节点1在输入字符e的情况下转换到节点2。


我们利用如下方法来求出g中所有节点的fail值。首先,令第1层节点的fail值都为0。然后,将第1层的节点依次加入队列queue尾部。然后,从队列queue的头部依次取出节点。对于取出的节点m,及其与子节点的状态转移g(m,i)=n,fail[n]的计算方法为,我们令fail[m]=p,如果p!=0且g(p,i)=0,我们令p=fail[p],直到p=0,或者g(p,i)!=0为止,此时fail[n]=g(p,i)。对于状态n,如果output[p]包含匹配的模式串,则将output[p]中的匹配的模式,全部加入output[n]中。如果节点n仍有子节点,则将节点n加入队列queue的尾部,直到队列queue中的所有节点处理完毕为止,我们就得到了除状态0之外的所有节点的fail值。下面举上图的三个例子说明。

1. fail[2]=g(fail[1],e)=g(0,e)=10,fail[6]=g(fail[1],i)=g(0,i)=0,这里对于第1层节点1,3,10,我们有fail[1]=0,fail[3]=0,fail[10]=0。

2. 对于fail[5],有g(4,e)=5,g(fail[4],e)=g(1,e)=2!=0,所以fail[5]=2,因为output[2]包含模式串he,所以我们要将output[2]中的内容添加到output[5]中,此时output[5]={she,he}。

3. 对于fail[9],我们有g(8,s)=9,g(fail[8],s)=g(11,s)=0,但是此时p=fail[8]!=0,所以我们接着考察fail[p]=fail[fail[8]]=fail[11]=0,此时fail[11]=0,g(fail[11],s)=g(0,s)=3,所以fail[9]的最终结果是3。由于节点3的output值为空,无需新增output[9]的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值