Aho-Corasick 多模式匹配算法、AC自动机详解
2013-11-20 14:25
281 查看
Aho-Corasick算法是多模式匹配中的经典算法,目前在实际应用中较多。
Aho-Corasick算法对应的数据结构是Aho-Corasick自动机,简称AC自动机。
搞编程的一般都应该知道自动机FA吧,具体细分为:确定性有限状态自动机(DFA)和非确定性有限状态自动机NFA。普通的自动机不能进行多模式匹配,AC自动机增加了失败转移,转移到已经输入成功的文本的后缀,来实现。
1.多模式匹配
多模式匹配就是有多个模式串P1,P2,P3...,Pm,求出所有这些模式串在连续文本T1....n中的所有可能出现的位置。
例如:求出模式集合{"nihao","hao","hs","hsr"}在给定文本"sdmfhsgnshejfgnihaofhsrnihao"中所有可能出现的位置。
2.Aho-Corasick算法
使用Aho-Corasick算法需要三步:
1.建立模式的Trie
2.给Trie添加失败路径
3.根据AC自动机,搜索待处理的文本
下面说明这三步:
2.1建立多模式集合的Trie树
Trie树也是一种自动机。对于多模式集合{"say","she","shr","he","her"},对应的Trie树如下,其中红色标记的圈是表示为接收态:
View Code
输出:
(上面的两个图,参考网页:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html)
Aho-Corasick算法对应的数据结构是Aho-Corasick自动机,简称AC自动机。
搞编程的一般都应该知道自动机FA吧,具体细分为:确定性有限状态自动机(DFA)和非确定性有限状态自动机NFA。普通的自动机不能进行多模式匹配,AC自动机增加了失败转移,转移到已经输入成功的文本的后缀,来实现。
1.多模式匹配
多模式匹配就是有多个模式串P1,P2,P3...,Pm,求出所有这些模式串在连续文本T1....n中的所有可能出现的位置。
例如:求出模式集合{"nihao","hao","hs","hsr"}在给定文本"sdmfhsgnshejfgnihaofhsrnihao"中所有可能出现的位置。
2.Aho-Corasick算法
使用Aho-Corasick算法需要三步:
1.建立模式的Trie
2.给Trie添加失败路径
3.根据AC自动机,搜索待处理的文本
下面说明这三步:
2.1建立多模式集合的Trie树
Trie树也是一种自动机。对于多模式集合{"say","she","shr","he","her"},对应的Trie树如下,其中红色标记的圈是表示为接收态:
#include<iostream> #include<string.h> #include<malloc.h> #include <queue> using namespace std; typedef struct node{ struct node *next[26]; //接收的态 struct node *par; //父亲节点 struct node *fail; //失败节点 char inputchar; int patterTag; //是否为可接收态 int patterNo; //接收态对应的可接受模式 }*Tree,TreeNode; char pattern[4][30]={"nihao","hao","hs","hsr"}; /** 申请新的节点,并进行初始化 */ TreeNode *getNewNode() { int i; TreeNode* tnode=(TreeNode*)malloc(sizeof(TreeNode)); tnode->fail=NULL; tnode->par=NULL; tnode->patterTag=0; for(i=0;i<26;i++) tnode->next[i]=NULL; return tnode; } /** 将Trie树中,root节点的分支节点,放入队列 */ int nodeToQueue(Tree root,queue<Tree> &myqueue) { int i; for (i = 0; i < 26; i++) { if (root->next[i]!=NULL) myqueue.push(root->next[i]); } return 0; } /** 建立trie树 */ Tree buildingTree() { int i,j; Tree root=getNewNode(); Tree tmp1=NULL,tmp2=NULL; for(i=0;i<4;i++) { tmp1=root; for(j=0;j<strlen(pattern[i]);j++) ///对每个模式进行处理 { if(tmp1->next[pattern[i][j]-'a']==NULL) ///是否已经有分支,Trie共用节点 { tmp2=getNewNode(); tmp2->inputchar=pattern[i][j]; tmp2->par=tmp1; tmp1->next[pattern[i][j]-'a']=tmp2; tmp1=tmp2; } else tmp1=tmp1->next[pattern[i][j]-'a']; } tmp1->patterTag=1; tmp1->patterNo=i; } return root; } /** 建立失败指针 */ int buildingFailPath(Tree root) { int i; char inputchar; queue<Tree> myqueue; root->fail=root; for(i=0;i<26;i++) ///对root下面的第二层进行特殊处理 { if (root->next[i]!=NULL) { nodeToQueue(root->next[i],myqueue); root->next[i]->fail=root; } } Tree tmp=NULL,par=NULL; while(!myqueue.empty()) { tmp=myqueue.front(); myqueue.pop(); nodeToQueue(tmp,myqueue); inputchar=tmp->inputchar; par=tmp->par; while(true) { if(par->fail->next[inputchar-'a']!=NULL) { tmp->fail=par->fail->next[inputchar-'a']; break; } else { if(par->fail==root) { tmp->fail=root; break; } else par=par->fail->par; } } } return 0; } /** 进行多模式搜索,即搜寻AC自动机 */ int searchAC(Tree root,char* str,int len) { TreeNode *tmp=root; int i=0; while(i < len) { int pos=str[i]-'a'; if (tmp->next[pos]!=NULL) { tmp=tmp->next[pos]; if(tmp->patterTag==1) ///如果为接收态 { cout<<i-strlen(pattern[tmp->patterNo])+1<<'\t'<<tmp->patterNo<<'\t'<<pattern[tmp->patterNo]<<endl; } i++; } else { if(tmp==root) i++; else { tmp=tmp->fail; if(tmp->patterTag==1) //如果为接收态 cout<<i-strlen(pattern[tmp->patterNo])+1<<'\t'<<tmp->patterNo<<'\t'<<pattern[tmp->patterNo]<<endl; } } } while(tmp!=root) { tmp=tmp->fail; if(tmp->patterTag==1) cout<<i-strlen(pattern[tmp->patterNo])+1<<'\t'<<tmp->patterNo<<'\t'<<pattern[tmp->patterNo]<<endl; } return 0; } /** 释放内存,DFS */ int destory(Tree tree) { if(tree==NULL) return 0; queue<Tree> myqueue; TreeNode *tmp=NULL; myqueue.push(tree); tree=NULL; while(!myqueue.empty()) { tmp=myqueue.front(); myqueue.pop(); for (int i = 0; i < 26; i++) { if(tmp->next[i]!=NULL) myqueue.push(tmp->next[i]); } free(tmp); } return 0; } int main() { char a[]="sdmfhsgnshejfgnihaofhsrnihao"; Tree root=buildingTree(); ///建立Trie树 buildingFailPath(root); ///添加失败转移 cout<<"待匹配字符串:"<<a<<endl; cout<<"模式"<<pattern[0]<<" "<<pattern[1]<<" "<<pattern[2]<<" "<<pattern[3]<<" "<<endl<<endl; cout<<"匹配结果如下:"<<endl<<"位置\t"<<"编号\t"<<"模式"<<endl; searchAC(root,a,strlen(a)); ///搜索 destory(root); ///释放动态申请内存 return 0; }
View Code
输出:
(上面的两个图,参考网页:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html)
相关文章推荐
- Aho-Corasick 多模式匹配算法、AC自动机详解
- Aho-Corasick 多模式匹配算法、AC自动机详解
- Aho-Corasick 多模式匹配算法、AC自动机详解
- ac自动机算法(Aho-Corasick 多模式匹配算法)
- Aho-Corasick 多模式匹配算法
- 多模匹配算法之Aho-Corasick
- KMP字符串模式匹配算法详解
- 【AC自动机】:Aho-Corasick算法的实现
- KMP模式匹配算法详解(耐心看完定会理解)
- 数据结构20:KMP算法(快速模式匹配算法)详解
- 模式匹配算法详解:KMP算法
- Aho-Corasick自动机算法(简称AC自动机
- 多模式串匹配之AC自动机算法(Aho-Corasick算法)简介与C语言程序实现源码参考
- 深入串的模式匹配算法(普通算法和KMP算法)的详解
- java 中模式匹配算法-KMP算法实例详解
- AC(Aho—Corasiek) 多模式匹配算法
- 串算法1 Trie+KMP+Aho-Corasick自动机(AC自动机)
- AC自动机-多模式匹配算法
- 多模匹配算法之Aho-Corasick
- 字符串模式匹配算法--详解KMP算法