议题:AC自动机(Aho-Corasick Automation)
分析:
-
此算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一;一个常见的例子就是给定N个单词,给定包含M个字符的文章,要求确定多少个给定的单词在文章中出现过;AC自动机在匹配文本时不需要回溯,处理时间复杂度与pattern无关,仅是target的长度O(N);构建AC自动机的时间复杂度;
-
与KMP算法类似,AC自动机也是利用前一个匹配模式串失效之后得到的信息来确定下一个匹配的开始位置,从而避免回移主串的匹配指针;与KMP算法不同的 是,AC自动机是针对多个模式串在同一个主串上的匹配,不仅在同一个模式串匹配内部,而且在不同的模式串之间利用前一次匹配失效的信息来确定下一次匹配的 开始位置;
AC自动机的构建主要由三个步骤:
-
针对所有模式串构建Trie树;
-
针对所有Trie树上的接点构建Fail指针:Fail指针指向的是如果当前节点匹配失败,则从通过Fail指针指向的新的节点开始匹配,但新的节点必须满足所在在新节点模式串的前缀必须是转移前的节点所在模式串的子串,也就是已经匹配成功的部分;
-
正式匹配过程:将主串在Trie树上匹配,主要有两种操作,如果当前节点匹配成功,则随机选择一条子路径到达的节点;如果当前节点匹配失败,则使用Fail指针转移到新的节点;知道文本末尾;
样例:
1 /** 2 * 定义Trie树中子节点的最大个数,26个英文字母 3 * */ 4 const int MAX_NUM=26; 5 /** 6 * 用于构造Fail指针的队列,队列元素为拥有三个数据域 7 * 的对象: 8 * fail表示Fail指针 9 * Child数组表示26个子节点指针 10 * IsOver表示当前节点是否为一个单词的结束节点 11 * */ 12 struct Node { 13 Node *fail; 14 Node *Child[MAX_NUM]; 15 int IsOver; 16 Node() { 17 fail=NULL; 18 IsOver=0; 19 for(int i=0;i<26;i++) 20 Child[i]=NULL; 21 } 22 } *queue[1000]; 23 /** 24 * pattern表示输入的单词 25 * target表示目标匹配文本 26 * */ 27 char pattern[100]; 28 char target[10000]; 29 30 /** 31 * head表示队列queue中的头结点,新元素入队的位置 32 * tail表示队列queue中的尾节点,元素出队的位置 33 * */ 34 int head; 35 int tail; 36 37 /** 38 * 首先利用pattern构建Trie树 39 * Trie树的根节点root是一个包含空字符的辅助节点; 40 * pointer指针遍历遍历Trie树 41 * temp指针临时替换一个节点的26个子节点中的一个 42 * index指针索引一个pattern中的字符 43 * 如果有多个pattern字符串,则需要多次调用此方法 44 * */ 45 void ConstructTrieTree(char *pattern, Node *root) { 46 Node *pointer=root; 47 Node *temp; 48 char *index=pattern; 49 /** 50 * 此处循环以需要插入Trie树的pattern字符串作为依据 51 * */ 52 while(*index!='