AC算法原理与实现(模式匹配)
2014-11-18 20:50
375 查看
最近学习模式匹配知识,了解了KMP与BM算法后,AC的了解也必不可少。上网学习了下,把重要的知识总结一下。
Aho_Corasick自动机匹配算法是最著名的多模式匹配算法之一。AC自动机算法分为3步:构造一颗Trie树,构造失败指针和模式匹配过程。
1.建立一颗Trie的过程比较简单(可参考源代码)
2.构造失败指针
构造失败指针的过程概括起来就一句话:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。
3.模式匹配过程
匹配过程分两种情况:
(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。
下面给出AC算法的具体C++实现:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1000001; //模式串的最大长度MAXN - 1
const int MAXM = 51; //单词最大长度为MAXM - 1
const int KEYSIZE = 26; //26个小写字母
struct Node {
Node *fail; //失败指针
Node *next[KEYSIZE]; //儿子结点个数
int count; //单词个数
Node() {
fail = NULL;
count = 0;
memset(next, 0, sizeof(next));
}
}*q[MAXN / 2];
void insert(char *str, Node *root)
{
Node *p = root;
int i = 0;
while(str[i]) {
int index = str[i] - 'a';
if(p -> next[index] == NULL)
p -> next[index] = new Node();
p = p -> next[index];
i ++;
}
p -> count ++; //在单词的最后一个结点count + 1,代表一个单词
}
void build_ac_automation(Node *root)
{
root -> fail = NULL;
int head, tail;
head = tail = 0;
q[tail ++] = root;
while(head < tail) {
Node *temp = q[head ++];
for(int i = 0; i < KEYSIZE; i ++) {
if(temp -> next[i] != NULL) {
if(temp == root) {
temp -> next[i] -> fail = root;
}else {
Node *p = temp -> fail;
while(p != NULL) {
if(p -> next[i] != NULL) {
temp -> next[i] -> fail = p -> next[i];
break;
}
p = p -> fail;
}
if(p == NULL)
temp -> next[i] -> fail = root;
}
q[tail ++] = temp -> next[i];
}
}
}
}
int AC_search(char *str, Node *root)
{
int i = 0, cnt = 0;
Node *p = root;
while(str[i]) {
int index = str[i] - 'a';
while(p -> next[index] == NULL && p != root) p = p -> fail;
p = p -> next[index];
p = (p == NULL) ? root : p;
Node *temp = p;
while(temp != root && temp -> count != -1) {
cnt += temp -> count;
temp -> count = -1;
temp = temp -> fail;
}
i ++;
}
return cnt;
}
int main()
{
int n;
Node *root;
char keyword[MAXM]; //单词
char str[MAXN]; //模式串
printf("scanf the number of words-->\n");
scanf("%d", &n);
root = new Node();
printf("scanf the words-->\n");
while(n --) {
scanf("%s", keyword);
insert(keyword, root);
}
build_ac_automation(root);
printf("scanf the text-->\n");
scanf("%s", str);
printf("there are %d words match\n", AC_search(str, root));
return(0);
}
Aho_Corasick自动机匹配算法是最著名的多模式匹配算法之一。AC自动机算法分为3步:构造一颗Trie树,构造失败指针和模式匹配过程。
1.建立一颗Trie的过程比较简单(可参考源代码)
2.构造失败指针
构造失败指针的过程概括起来就一句话:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。
3.模式匹配过程
匹配过程分两种情况:
(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。
下面给出AC算法的具体C++实现:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1000001; //模式串的最大长度MAXN - 1
const int MAXM = 51; //单词最大长度为MAXM - 1
const int KEYSIZE = 26; //26个小写字母
struct Node {
Node *fail; //失败指针
Node *next[KEYSIZE]; //儿子结点个数
int count; //单词个数
Node() {
fail = NULL;
count = 0;
memset(next, 0, sizeof(next));
}
}*q[MAXN / 2];
void insert(char *str, Node *root)
{
Node *p = root;
int i = 0;
while(str[i]) {
int index = str[i] - 'a';
if(p -> next[index] == NULL)
p -> next[index] = new Node();
p = p -> next[index];
i ++;
}
p -> count ++; //在单词的最后一个结点count + 1,代表一个单词
}
void build_ac_automation(Node *root)
{
root -> fail = NULL;
int head, tail;
head = tail = 0;
q[tail ++] = root;
while(head < tail) {
Node *temp = q[head ++];
for(int i = 0; i < KEYSIZE; i ++) {
if(temp -> next[i] != NULL) {
if(temp == root) {
temp -> next[i] -> fail = root;
}else {
Node *p = temp -> fail;
while(p != NULL) {
if(p -> next[i] != NULL) {
temp -> next[i] -> fail = p -> next[i];
break;
}
p = p -> fail;
}
if(p == NULL)
temp -> next[i] -> fail = root;
}
q[tail ++] = temp -> next[i];
}
}
}
}
int AC_search(char *str, Node *root)
{
int i = 0, cnt = 0;
Node *p = root;
while(str[i]) {
int index = str[i] - 'a';
while(p -> next[index] == NULL && p != root) p = p -> fail;
p = p -> next[index];
p = (p == NULL) ? root : p;
Node *temp = p;
while(temp != root && temp -> count != -1) {
cnt += temp -> count;
temp -> count = -1;
temp = temp -> fail;
}
i ++;
}
return cnt;
}
int main()
{
int n;
Node *root;
char keyword[MAXM]; //单词
char str[MAXN]; //模式串
printf("scanf the number of words-->\n");
scanf("%d", &n);
root = new Node();
printf("scanf the words-->\n");
while(n --) {
scanf("%s", keyword);
insert(keyword, root);
}
build_ac_automation(root);
printf("scanf the text-->\n");
scanf("%s", str);
printf("there are %d words match\n", AC_search(str, root));
return(0);
}
相关文章推荐
- 模式匹配 -- KMP 算法原理与实现
- AC-BM算法原理与代码实现(模式匹配)
- KMP模式匹配算法原理分析、next数组优化及java实现
- AC-BM算法原理与代码实现(模式匹配)
- AC-BM算法原理与代码实现(模式匹配)
- 多模式匹配算法:AC自动机的C++实现
- AC-BM算法原理与代码实现(模式匹配)
- AC-BM算法原理与代码实现(模式匹配)
- 【模式匹配】之——多模匹配 上篇(AC算法)
- BM模式匹配算法-原理(图解)
- KMP串匹配算法原理及实现
- AC算法--多模式匹配(论文解析版)
- KMP模式匹配算法 C++实现
- 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一网打尽
- 【模式匹配】之——多模匹配 上篇(AC算法)
- 经典算法研究:模式匹配(子串匹配)之 BM 算法(C语言实现版)初版
- AC 多模式匹配算法
- BM模式匹配算法-实现(C语言)
- KMP字符串模式匹配算法实现(php)
- AC 经典多模式匹配算法