AC自动机的简单实现

AC自动机是著名的多模式匹配算法,给出n个单词和一篇含有m个单词的文章,找出n个单词中有多少是在文章中出现过。

AC自动机的构造分为三步:构造trie树,构造fail指针,模式串匹配。而常用的单模式串匹配主要用kmp算法,多模式匹配与之有相似之处,因此要学习AC自动机,需要有trie树和kmp算法的知识。

下边链接中有对AC自动机以及它的构造比较清晰的描述,笔者也是在一次面试中第一次接触到AC自动机,学习之后特来实现一下

http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

  1 HDU 2222
  2 
  3 #include <stdio.h>
  4 
  5 struct node
  6 {
  7     node * fail;
  8     node * next[26];
  9     int flag;
 10     node()
 11     {
 12         fail=NULL;
 13         for(int i=0;i<26;i++)
 14            next[i]=NULL;
 15         flag=0;
 16     }
 17 };
 18 
 19 char content[1000001];
 20 char seq[51];
 21 node * que[510000];
 22 
 23 void insert(char * str,node * root)
 24 {
 25     node * p = root;
 26     int t;
 27     while(*str)
 28     {
 29         t=*str-'a';
 30         if(p->next[t]==NULL)
 31             p->next[t]=new node();
 32         p=p->next[t];
 33         str++;
 34     }
 35     p->flag++;
 36 }
 37 
 38 void build_ac(node * root)
 39 {
 40     node *p,*q;
 41     int head,tail;
 42     head=tail=0;
 43     root->fail=NULL;
 44     que[head++]=root;
 45     while(tail<head)
 46     {
 47         p=que[tail++];
 48         for(int i=0;i<26;i++)
 49         {
 50             if(p->next[i])
 51             {
 52                 if(p==root)
 53                     p->next[i]->fail=root;
 54                 else
 55                 {
 56                     q=p->fail;
 57                     while(q!=NULL)
 58                     {
 59                         if(q->next[i])
 60                         {
 61                             p->next[i]->fail=q->next[i];
 62                             break;
 63                         }
 64                         q=q->fail;
 65                     }
 66                     if(q==NULL)
 67                         p->next[i]->fail=root;
 68                 }
 69                 que[head++]=p->next[i];
 70             }
 71         }
 72     }
 73 }
 74 
 75 int query(char * content,node * root)
 76 {
 77     node * p = root,*q,*tmp;
 78     int cnt=0;
 79     int t;
 80     while(*content)
 81     {
 82         t=*content-'a';
 83         while(p!=NULL && p->next[t]==NULL)
 84             p=p->fail;
 85         if(p==NULL)
 86             p=root;
 87         else
 88         {
 89             p=p->next[t];
 90             q=p;
 91             while(q!=root)
 92             {
 93                 if(q->flag>0)
 94                 {
 95                     cnt+=q->flag;
 96                     q->flag=-1;
 97                 }
 98                 q=q->fail;
 99             }
100         }
101         content++;
102     }
103     return cnt;
104 }
105 
106 int main(int argc, char * argv[])
107 {
108     freopen("in","r",stdin);
109     int t,n;
110     scanf("%d",&t);
111     while(t--)
112     {
113         scanf("%d",&n);
114         node * root = new node();
115         for(int i=0;i<n;i++)    //构建trie树
116         {
117             scanf("%s",seq);
118             insert(seq,root);
119         }
120         scanf("%s",content);
121         build_ac(root);         //构造fail指针
122         printf("%d\n",query(content,root));  //模式串匹配
123     }
124     return 0;
125 }
原文地址:https://www.cnblogs.com/qianye/p/3065454.html