多模式串匹配之AC自动机算法_第1页
多模式串匹配之AC自动机算法_第2页
多模式串匹配之AC自动机算法_第3页
多模式串匹配之AC自动机算法_第4页
多模式串匹配之AC自动机算法_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、多模式串匹配之AC自动机算法(Aho-Corasick算法)简介与C语言程序实现源码参考· 任侠 发布于 2011-03-22  22:27:53  一、概述AC自动机算法全称Aho-Corasick算法,是一种字符串多模式匹配算法。该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。AC算法用于在一段文本中查找多个模式字符串,即给你很多字符串,再给你一段文本,让你在文本中找这些串是否出现过,出现过多少次,分别在哪里出现。该算法应用有限自动机巧妙地将字符比较转化为了状态转移。此算法有两个特点,一个是扫描文本时完全不需要回溯,另一个是时间复杂度为

2、O(n),时间复杂度与关键字的数目和长度无关,但所需时间和文本长度以及所有关键字的总长度成正比。AC算法有三个主要步骤,一个是字典树tire的构造,一个是搜索路径的确定(即构造失败指针),还有就是模式匹配过程。学习AC自动机算法之前,最好先熟悉KMP算法,因为KMP算法与字典树tire的构造很是类似。KMP算法是一种经典的单字符串匹配算法。二、AC算法思想 AC算法思想:用多模式串建立一个确定性的树形有限状态机,以主串作为该有限状态机的输入,使状态机进行状态的转换,当到达某些特定的状态时,说明发生模式匹配。下图是多模式he/ she/ his /hers构成的一个确定性有限状态机,做

3、几点说明:图2.11、 该状态机优先按照实线标注的状态转换路径进行转换,当所有实线标注的状态转换路径条件不能满足时,按照虚线的状态转换路径进行状态转换。如:状态0时,当输入h,则转换到状态1;输入s,则转换到状态3;否则转换到状态0。2、 匹配过程如下:从状态0开始进行状态转换,主串作为输入。如主串为:ushers,状态转换的过程是这样的:图2.23、 当状态转移到2,5,7,9等红色状态点时,说明发生了模式匹配。如主串为:ushers,则在状态5、2、9等状态时发生模式匹配,匹配的模 式串有she、he、hers。定义:在预处理阶段,AC自动机算法建立了三个函数,转向函数goto,

4、失效函数failure和输出函数output,由此构造了一个树型有限自动机。转向函数,指的是一种状态之间的转向关系。g(pre, x)=next:状态pre在输入一个字符x后转换为状态next(上图中的实线部分)。如果在模式串中不存在这样的转换,则next=failstate。失效函数,指的也是状态和状态之间一种转向关系。f(per)=next:是在比较失配的情况下使用的转换关系。在构造转向函数时,把不存在的转换用failstate表示,但是failstate不是一个具体的状态,状态机转换转换到failstate状态的时候就不知道该往哪转了。所以就要在状态机中找到一个有意义的状态代替fails

5、tate,当出现failstate状态时,自动切换到那个状态。这个状态节点应该具有这样的特征:从这个状态节点向上直到树根节点(状态0)所经历的输入字符,和从产生failstate状态的那个状态节点向上所经历的输入字符串完全相同。而且这个状态节点,是所有具备这些条件的节点中深度最大的那个节点。如果不存在满足条件的状态节点,则失效函数为0。累死了。举例子说吧,对状态9输入任何一个字符都会产生failstate状态,需要失效函数。状态3向上到状态0经过的输入字符串为s;而由状态9向上的输入字符串为sreh。字符串s相同,并且状态3是满足此条件的唯一节点,则f(9)=3。说来说去,失效函数就是要干这么

6、件事儿:图2.3意思就是说,在比较模式串1发生失配时,找一个模式串2,使得P20.j-1 = P1i-j+1.i。然后继续比较模式串2。看上面那个图,想起点儿什么东西没有?对了,是KMP算法。有人说AC算法就是KMP算法在多模式匹配情况下的扩展。输出函数,指的是状态和模式串之间的一种关系。output(i)=P,表示当状态机到达状态i时,模式串集合P中的所有模式串可能已经完成匹配。 例:模式串为:he/ she/ hers/ his 时,如图2.4所示。转向函数:图2.4失效函数:图2.5输出函数:图2.6 三、字典树tire的构造这个比较好理解,就是把要匹配的一些字符串添

7、加到树结构中去。树边就是单词中的字符,单词中最后一个字符的连接节点添加标志,以表示改节点路径包含1个字典中的字符串,搜索到此节点就表示找到了字典中的某个单词,可以直接输出。Trie是一个树形结构的状态装换图,从一个结点到它的各个子结点的边上有不同的标号。Trie的叶子结点表示识别到的关键字。当我们的模式串在Tire上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。例子:某字典P=he,she,his,hers对应的字典树如下图:图3.1图中有数字的节点到根节点的路劲正好对应字典中的字符串,数字表述单词在字典中的顺序,也可以是其他标志。四

8、、搜索路径的确定我的理解是:利用后缀字符串来确定。后缀字符串就是某个字符串的后面的一部分。比如abcde的后缀字符串有bcde,cde,de和e。假定目标字符串为ushers,字典为上图(图1)所示。搜索过程目标字符串指针指向的字符和字典中的字符会有以下几种情况:a. 当前字符匹配。表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;如:当指针指到s处,此时字典树指针处于根,要从根到s处,可以看到图中有一条从根经s连接到的节点,因此字典树节点指针指向此节点,目标字符串指针移动到下一字符h继续匹配;显然当前节点有一条经

9、h连接到的节点,于是重复操作到有数字标志的节点2处,表示已找到,该匹配字符串就是"she",输出该字符串的位置后,目标字符串指针增1指向"r",字典指针指向数字2节点,进行下次匹配。b. 当前字符无匹配。表示当前节点的任何一条边都无法达到要匹配的字符,此时不能沿现有路径前进,只能回溯,回溯到存在的最长的后缀字符串处,如果没有任何后缀字符串匹配则回溯到树根处。然后从当前回溯节点判断是否可以到达目标字符串字符。如:接上,由于数字2节点无经"r"的连接,因此回溯,she的后缀字符串he在字典树中,因此字典树指针指向带有数字1的标志节点,由于

10、带有标志,直接输出该节点"HE"(存疑,很多文章没有提到此处需要输出,正常路径移动的字典指针节点要判断是否可以输出,那么由回溯路径改变的字典指针指向的节点要不要判断是否输出?),然后从数字1节点判断是否有经"r"到下一节点的路径,显然图中有。因此字典树节点指向下一节点,重复以上操作,最后找到"hers",此时匹配搜索也结束了。以上两种情况直到目标字符串指针直到末尾结束匹配。在匹配过程中遇到有标志的节点说明找到了字典中的某个词,可以直接输出。 输出说明:每次目标串指针移动前都需要判断当前节点是否可以输出,并递归的判断当前节点回

11、溯路径上的节点是否可以输出(其实就是判断所有后缀字符串,she匹配时,其后缀he也会匹配,即使she不匹配,其后缀he也可能匹配,因此需递归判断后缀字符串),直到树根结束递归。由于固定字典的字符串的后缀字符串都是已知的,因此可以在字典树结构中存储匹配失败的路径方向,因此只要字典树构造完毕,就可以根据字典树的路径进行匹配了,效率非常快。以上就是我对该算法的全部过程的理解,疏漏之处在所难免。附录:附1:含匹配失败的情况的路径选择的字典树,实线表示匹配成功的正常路径,虚线表示失败的回溯路径图 附1.1附2:AC算法的伪代码实现描述T为目标字符串,长度为m,q为字典树的节点指针,g函数返回从节点q经过

12、路径Ti到达的下一节点指针,f函数返回节点q的回溯节点指针。flag判断节点是否为标志节点q := 0; / initial state (root)for i := 1 to m do    while g(q,Ti) = NULL do        q := f(q); / 回溯    q := g(q,Ti); / 前进    node:=q;    while(node!=root)&#

13、160;       if flag(node) exist ; then print i, out(node);        node = f(node);   /查找回溯节点    end for;   附3:一个简单的AC算法实现源码示例参考: /*程序说明:多模式串匹配的AC自动机算法自动机算法可以参考柔性字符串匹配里的相应章节,讲的很清楚*/#include <

14、;stdio.h>#include <string.h>  const int MAXQ = 500000+10;const int MAXN = 1000000+10;const int MAXK = 26; /自动机里字符集的大小struct TrieNode       TrieNode* fail;       TrieNode* nextMAXK;  

15、0;    bool danger;   /该节点是否为某模式串的终结点       int cnt;    /以该节点为终结点的模式串个数       TrieNode()                   

16、;  fail = NULL;              memset(next, NULL, sizeof(next);              danger = false;            

17、60; cnt = 0;       *queMAXQ, *root;/文本字符串char msgMAXN;int   N;void TrieInsert(char *s)       int i = 0;       TrieNode *ptr = root;       while(si) &#

18、160;                   int idx = si-'a'              if(ptr->nextidx = NULL)         

19、0;           ptr->nextidx = new TrieNode();              ptr = ptr->nextidx;              i+;   

20、60;          ptr->danger = true;       ptr->cnt+; void Init()       int i;       char s100;       root = new TrieN

21、ode();       scanf("%d", &N);       for(i = 0; i < N; i+)                     scanf("%s", s);    &

22、#160;         TrieInsert(s);        void Build_AC_Automation()       int rear = 1, front = 0, i;       que0 = root;       roo

23、t->fail = NULL;       while(rear != front)                     TrieNode *cur = quefront+;              for(

24、i = 0; i < 26; i+)                     if(cur->nexti != NULL)                       

25、                          if(cur = root)                      

26、60;            cur->nexti->fail = root;                            else     

27、60;                                                  &#

28、160;      TrieNode *ptr = cur->fail;                                   while(ptr != NULL)  &

29、#160;                                                  

30、                        if(ptr->nexti != NULL)                      

31、0;                                                  

32、60;                 cur->nexti->fail = ptr->nexti;                           

33、;                      if(ptr->nexti->danger = true)                       

34、;                                 cur->nexti->danger = true;            &#

35、160;                                    break;             &

36、#160;                                                  

37、                    ptr = ptr->fail;                           

38、0;                                          if(ptr = NULL) cur->nexti->fail = root;  

39、;                                                  

40、0;   querear+ = cur->nexti;                            int AC_Search()       int i = 0, ans = 0;   

41、60;   TrieNode *ptr = root;       while(msgi)                     int idx = msgi-'a'           &#

42、160;  while(ptr->nextidx = NULL && ptr != root) ptr = ptr->fail;              ptr = ptr->nextidx;              if(ptr = NULL) ptr = root;              TrieNode *tmp = ptr;              while(tmp != NULL && tmp->cnt != -1)              

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论