关于AC自动机的思考

关于 AC自动机的思考


之前看到HDOJ上那道病毒侵入题,了解到了AC自动机,查了很多资料,于是记录一下对AC自动机的一些理解。


前提

AC自动机是基于KMP算法和字典树扩展过来的,通过减少冗余匹配来减少算法复杂度。
  • KMP算法通过加大比对指针跳跃距离,越过理论上已知无需进行判断的位置,从而加快比对速度。
  • 字典树通过利用各个单词的公共前缀减少比对次数

基本思路

考虑一个例子:
    单词:he / she / his / hers
    文本:ushers

对应的字典树如图所示
(来源:深入理解Aho-Corasick自动机算法)
图非原创

  • 对比原朴素字典树查找方法:
    • 先查找u,发现字典树根节点并没有此字母,退出。
    • 再查找s,发现根节点上有s字母,继续。
    • 查找h,发现s节点下也有h,于是继续。
    • 再查找e,发现h节点下有e,并且e节点上标记了一个“she”单词,于是记录。
    • 再查找r,发现e下不再有r了,于是退出。
    • 再对文本的h开始重复以上几步查找,直至结束。
对朴素查找的分析
  • 朴素查找每次在文本中查找单词时,都会选取以当前字母开始到末尾的一个子字符串,然后对该子字符串进行查找,完毕后“当前字母”向前移动一个距离并继续下一次子字符串的判断。
  • 注意到一个问题:对于单词 “she” 和 “he” 而言,已知的一个事实是,如果查找到文本内有一段“she”的文本,那么首先会知道文本中存在一个单词“she”,但同时,在查找”s”->”h”->”e”树枝时理应知道单词“he”也出现了。所以,只需要在这时直接将这个已知信息记录即可,之后就没必要再在查找以“h”开头的文本子字符串时再查找“he”这个单词了。AC自动机某种意义上减少了这部分冗余的查找,并且顺利地跳转到了查找下一个字母时应该搜索的树枝(这里仅为个人认知,并不一定正确),有一种利用了公共后缀的意味
  • 相当于在查找下一个子字符串时直接从非公共部分开始查找,而不是直接移动到下一个字符。
对AC自动机的分析
  • AC自动机对字典树的每一个节点添加了一个失配指针
  • 按照其他博客上的描述:构造失配指针的规则为:
    • 对于每一个节点A,寻找其父节点B的失配指针指向的节点C,再将A的失配指针指向C直接子节点中与A字母相同的节点。
    • 用另外一位博主的话说,就是指向到达该节点所表示的字符串的最长后缀子字符串的末节点。
  • 这样的话在搜索时,比如文本“she”,在查找到单词“she”后,这个树枝理应到达结尾然后退出,
    • 但通过失配指针,这个单词“she”树枝“e”节点的失配指针会指向“he”树枝的“e”,这样就能跳到“he”树枝,并发现“he”这个单词出现在文本中。
    • 然后处理文本下一个字母(这里为“r”)时,就会在”h”->”e”->”r”->”s”这个树枝上查找,就相当于结束了对“s”开头的文本子字符串的查找。

结语

仅为个人感悟,并不保证完全正确。

你可能感兴趣的:(算法,AC自动机,个人理解)