ac自动机可以看成带指针的字典树,每个节点的指针指向了当前节点的最大后缀的位置。在建立字典树后,可以层次遍历字典树来构建fail指针,根节点的直接孩子(第一层节点)的fail指针肯定是指向根节点的,之后的节点需要看其父节点的fail指针指向的节点,如果父节点的fail指针指向的节点的孩子中存在当前节点,则将当前节点的fail指针指向该节点,如果不存在,需要沿着fail指针一直向上寻找直至根节点,如果根节点的孩子中也找不到,说明树中不存在该字符,将当前节点的fail指针指向根节点就行了。最后,在查找时也类似,如果当前节点的孩子中查不到,也需要沿着fail指针行走直至根节点。举个例子,关键字[“i”, “is”,“ssippi”]建好树并构建好fail指针后如下图所示:
上图中,右边的第一个i,父节点的fail指针指向第一个s,但该s的孩子中并不存在i,所以需要沿着fail指针向上查找,发现根节点root下存在i,因此fail指针指向这个i。另外,若节点代表了关键词的结尾,则标记了该词的长度,如果该节点的fail指针指向的节点也有长度,则将长度合并至该节点(见上图右下角的i),以便于最后按照长度查找关键词。以下是python实现的代码:
from queue import Queue
from typing import List, Dict, Iterable
class AhoCorasick(object):
class Node(object):
def __init__(self, name: str):
self.name = name # 节点代表的字符
self.children = {
} # 节点的孩子,键为字符,值为节点对象
self.fail = None # fail指针,root的指针为None
self.exist = [] # 如果节点为单词结尾,存放单词的长度
def __init__(self, keywords: Iterable[str] = None):
"