“Aho–Corasick 自动机的输出链把每个报告步骤记给一个匹配,因而扫描是 $O(n+z)$;若只需每个模式的出现次数,可以累计状态访问数再沿失败树汇总,未必需要逐个生成全部 $z$ 个…”
形式陈述
给定带编号的非空模式列表
对非根节点
其中较浅状态的转移已经完成。完整转移函数是
读完文本前缀后,状态始终对应“既为当前文本后缀、又为某模式前缀”的最长串。转移复用仍可能延续的后缀,再加入新字符,按已读长度归纳即保持这一不变量。当前节点以及其失败链上的终止节点,恰好列出本位置结束的所有模式。输出链接指向失败链上最近的终止节点,可逐个跳到真正有输出的节点;每到一处报告其全部模式编号,无须复制整条失败链的输出列表。
把“当前状态或失败链上有终止节点”的状态设为接受态,就得到识别“以某模式结束”的完整 DFA;附在这些状态上的编号列表另外承担多模式报告。扫描长度
直觉
单模式匹配中,KMP 算法用前缀函数记住“失配之后还能保留多长的已匹配前缀”;Aho–Corasick 把这一思想搬到模式集合上:Trie 同时记住所有模式的所有前缀,失败链接则回答“当前候选走不下去时,次长的候选是谁”。关键图像是状态即匹配进度——自动机始终维护文本当前后缀所能匹配到的最深 Trie 节点,失配时不从头再来,而是退到进度稍浅、但仍然成立的候选上。于是无论模式有多少个,文本只需从左到右读一遍。
例子与边界
取经典模式集 he、she、his、hers,扫描文本 ushers:读 u 停在根;读 s、h、e 依次走到节点 she,在此报告模式 she,且该节点的失败链接指向 he,输出链接使 he 同时被报告;再读 r,节点 she 无 r 边,沿失败链接退到 he 后走 r 边得 her;最后读 s 到达 hers 并报告之。可见较短模式 he 完全藏在失败链上——只报告当前节点自身会漏掉它,这是最常见的实现错误;而逐位置沿失败链逐个上溯又可能把单字符代价拖到与深度成正比,输出链接把这一步压缩到与实际报告数成正比。
稠密转移表让每字符只查一次表,但在大字母表下可能浪费空间。只存
嵌套模式能更清楚地展示输出链。取模式 a、aa、aaa,扫描文本 aaaa:读到第一个字符时报告 a;第二个位置报告 a 与 aa;第三、第四个位置都分别报告三个、三个模式,因此匹配总数为
自动机的状态转移仍只随文本长度线性增长,但输出这些命中本身就需要
推论与应用
Aho–Corasick 是多模式字符串匹配的标准工具:敏感词过滤、入侵检测的特征扫描、词典与基因序列匹配,都靠它一次扫描文本、同时命中全部模式。把自动机状态当作“当前匹配进度”,还可与动态规划组合,解决统计不含任何禁止子串的字符串个数一类问题。失败链接全体构成一棵树(fail 树),在其上做子树统计,能一次性回答“每个模式在文本中出现了多少次”。实现词法分析等任务时,稠密字母表可预填完整转移表,稀疏字母表则需在空间与失败跳转代价之间权衡。
它与静态全文索引解决的是不同工作负载。Aho–Corasick 预处理模式集、随后在线顺序读文本,以上 count、locate 与 extract 的不同时间—空间成本。选择哪条路线取决于“模式固定还是文本固定”,不能只比较一句笼统的“线性匹配”。
参考资料
- Alfred V. Aho, Margaret J. Corasick, Efficient String Matching: An Aid to Bibliographic Search (1975), original multiple-pattern algorithm.
- OI-Wiki contributors, OI-Wiki (2026), Aho–Corasick automaton.