Skip to content

模型Model

Aho–Corasick 自动机

Aho–Corasick automaton · AC automaton

把模式 Trie 与失败链接结合成一次扫描识别多个模式的确定有限自动机。

形式陈述 ​

给定带编号的非空模式列表 p1,…,pk,允许不同编号的模式内容相同。记总字符数为 m。先把模式插入Trie,节点对应不同模式前缀,包括表示空前缀的根;终止节点保存全部对应模式编号。设节点数为 q,则 q≤m+1。空模式另行处理:每个空模式编号都应在文本的全部边界报告。

对非根节点 v,失败链接 fail(v) 指向 str(v) 的最长真后缀中仍为模式前缀的节点。令 fail(root)=root,根的孩子也都指向根。其他失败边严格降低深度,因此可用广度优先搜索构造:若 Trie 边 v→cw 的父节点不是根,则

fail(w)=δ(fail(v),c),

其中较浅状态的转移已经完成。完整转移函数是

δ(v,c)={w,Trie 中有边 v→cw,root,v=root 且没有该边,δ(fail(v),c),其他情况.

读完文本前缀后,状态始终对应“既为当前文本后缀、又为某模式前缀”的最长串。转移复用仍可能延续的后缀,再加入新字符,按已读长度归纳即保持这一不变量。当前节点以及其失败链上的终止节点,恰好列出本位置结束的所有模式。输出链接指向失败链上最近的终止节点,可逐个跳到真正有输出的节点;每到一处报告其全部模式编号,无须复制整条失败链的输出列表。

把“当前状态或失败链上有终止节点”的状态设为接受态,就得到识别“以某模式结束”的完整 DFA;附在这些状态上的编号列表另外承担多模式报告。扫描长度 n 的文本并输出 z 次匹配时,常数字母表下构建为 O(m+1),扫描为 O(n+z+1)。若为每个节点显式开 σ=|Σ| 项转移表,更完整的构建时间是 O(m+qσ),存储为 O(qσ+k) 个机器字,另计输入与输出。

直觉

单模式匹配中,KMP 算法用前缀函数记住“失配之后还能保留多长的已匹配前缀”;Aho–Corasick 把这一思想搬到模式集合上:Trie 同时记住所有模式的所有前缀,失败链接则回答“当前候选走不下去时,次长的候选是谁”。关键图像是状态即匹配进度——自动机始终维护文本当前后缀所能匹配到的最深 Trie 节点,失配时不从头再来,而是退到进度稍浅、但仍然成立的候选上。于是无论模式有多少个,文本只需从左到右读一遍。

Aho–Corasick:Trie、fail 与多模式报告
例子与边界

取经典模式集 he、she、his、hers,扫描文本 ushers:读 u 停在根;读 s、h、e 依次走到节点 she,在此报告模式 she,且该节点的失败链接指向 he,输出链接使 he 同时被报告;再读 r,节点 she 无 r 边,沿失败链接退到 he 后走 r 边得 her;最后读 s 到达 hers 并报告之。可见较短模式 he 完全藏在失败链上——只报告当前节点自身会漏掉它,这是最常见的实现错误;而逐位置沿失败链逐个上溯又可能把单字符代价拖到与深度成正比,输出链接把这一步压缩到与实际报告数成正比。

稠密转移表让每字符只查一次表,但在大字母表下可能浪费空间。只存 q−1 条 Trie 边、失败链接、输出链接与终止编号时,存储为 O(q+k) 个记录。扫描中每次成功沿 Trie 边至多增加一层深度,失败跳转则严格降低深度,因此整段文本共做 O(n) 次孩子字典查询;每次字典查询为常数成本时,才得到 O(n+z)。哈希字典通常给期望界,有序字典一般再带 log⁡(σ+1) 因子。这个扫描计费不直接证明稀疏失败表也能线性构建;构建阶段的转移查询须另行分析。

嵌套模式能更清楚地展示输出链。取模式 a、aa、aaa,扫描文本 aaaa:读到第一个字符时报告 a;第二个位置报告 a 与 aa;第三、第四个位置都分别报告三个、三个模式,因此匹配总数为

4+3+2=9.

自动机的状态转移仍只随文本长度线性增长,但输出这些命中本身就需要 Θ(9) 时间;一般复杂度必须写成 O(|T|+总模式长度+z),其中 z 是实际报告数。空模式在预处理时单独记录,其每个编号都会贡献 n+1 次边界匹配。重复的非空模式共享 Trie 路径,但保留各自编号;只有布尔终止标记无法表达这种逐编号报告。

推论与应用

Aho–Corasick 是多模式字符串匹配的标准工具:敏感词过滤、入侵检测的特征扫描、词典与基因序列匹配,都靠它一次扫描文本、同时命中全部模式。把自动机状态当作“当前匹配进度”,还可与动态规划组合,解决统计不含任何禁止子串的字符串个数一类问题。失败链接全体构成一棵树(fail 树),在其上做子树统计,能一次性回答“每个模式在文本中出现了多少次”。实现词法分析等任务时,稠密字母表可预填完整转移表,稀疏字母表则需在空间与失败跳转代价之间权衡。

它与静态全文索引解决的是不同工作负载。Aho–Corasick 预处理模式集、随后在线顺序读文本,以上 O(m+n+z+1) 是常字母表 RAM 下的确定性最坏输出敏感界;后缀树与Burrows–Wheeler 变换则预处理固定文本以服务许多模式查询。rank/select把 BWT 变成可导航序列,FM-index进一步用压缩自索引换取 count、locate 与 extract 的不同时间—空间成本。选择哪条路线取决于“模式固定还是文本固定”,不能只比较一句笼统的“线性匹配”。

参考资料
关系图谱12 个相邻概念 · 3 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系

使用的工具

实现的抽象