一:概念

首先简要介绍一下AC自己主动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之中的一个。一个常见的样例就是给出n个单词,再给出一段文章(长度是m),让你找出有多少个单词在文章里出现过。

要搞懂AC自己主动机。先得有字典树Trie的基础知识(也有人说需要KMP的知识,我认为暂且不要理会这个。

可是在看这篇文章之前,Trie字典树,你是必需要先搞懂,假设你还不理解Trie,请參考http://blog.csdn.net/laojiu_/article/details/50838421)。

与其它字符匹配不同,KMP算法是单模式串的字符匹配算法,AC自己主动机是多模式串的字符匹配算法。匹配时间复杂度是O(N)。线性复杂度!

二:算法过程(三步走)

举个样例,假如如今给出5个模式串:say she shr he her

主串是:yasherhs

如今问你,这5个模式串有几个出如今主串里的?

OK,如今就拿这个样例来完毕这个算法的过程。

第一步:构建Trie树,这非常easy的了。

构建好后。出现下图:

第二步:构建失败指针

构建失败指针是AC自己主动机的核心所在,玩转了它也就玩转了AC自己主动机,失败指针就是。当我的主串在trie树中进行匹配的时候,假设当前节点不能再继续进行匹配。那么我们就会走到当前节点的fail节点继续进行匹配。

构造失败指针的过程概括起来就一句话:对于root的儿子节点。fail指针直接指向root,其它的全部节点(用到了BFS和队列),设这个节点上的字母为C。沿着它父亲的失败指针走。直到走到一个节点,它的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母为C的节点。

假设一直走到了root都没找到,那就把失败指针指向root。

构建好后,例如以下图:

针对图中红线的”h。e“这两个节点。我们想起了什么呢?对”her“中的”e“来说,e到root距离的n个字符恰好与”she“中的e向上的n个字符相等。

第三步:模式匹配

匹配过程分两种情况:

(1)  当前字符匹配成功,表示从当前节点沿着树边有一条路径能够到达目标字符,此时仅仅需沿该路径走向下一个节点继续匹配就可以,目标字符串指针移向下个字符继续匹配;

(2)  当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。反复这2个过程中的随意一个。直到模式串走到结尾为止。

注意:主串全部字符在匹配完后都必需要走fail节点来结束自己的旅途,相当于一个回旋,这样做的目的防止包括节点被忽略掉。

见下图,比方:我匹配到了"she",必定会匹配到该字符串的后缀”he",要想在程序中匹配到,则必须节点要走失败指针来结束自己的旅途。

三:完整代码

#include<iostream>
#include<queue> #define MAX 26//如果仅仅出现26个小写英文字母
#define ROW 4
#define COLUMN 10 using namespace std; char pattern[ROW][COLUMN] = { "nihao","hao","hs","hsr" };
char *s = "sdmfhsgnshejfgnihaofhsrnihao"; struct Node
{
int index;//存储模式串的下标
char x;
Node *parent;
Node *next[MAX];
Node *fail;
Node()
{
index = -1;//pattern数组下标从0開始,-1代表该节点不是单词结尾
fail = nullptr;
parent = nullptr;
for (int i = 0; i < MAX; i++)
next[i] = nullptr;
}
}; class ACTree
{
public:
Node *root;
ACTree() { root = new Node; root->fail = root; } void Add(const char *ch, int index); //第一步
void NodeToQueue(Node *node, queue<Node*> &q); //
void BuildFailPointer(); //第二步
void ACSearch(const char *s); //第三步
}; int main()
{
ACTree tree; for (int i = 0; i < ROW; i++)
tree.Add(pattern[i], i); tree.BuildFailPointer(); cout << "待匹配字符串为(依次5个一组的输出):\n";
for (int i = 1; i <= strlen(s); i++)
{
cout << s[i];
if (i % 5 == 0)
cout << " ";
}
cout << endl << endl; cout << "匹配结果例如以下:\n";
cout << "位置\t" << "编号\t" << "模式\n"; tree.ACSearch(s); return 0;
} void ACTree::Add(const char *ch,int index)
{
int len = strlen(ch);
if (len == 0) return; Node *p = root; for (int i = 0; i < len; i++)
{
int k = ch[i] - 'a'; if (p->next[k] == nullptr)
{
p->next[k] = new Node;
p->next[k]->parent = p;
p->next[k]->x = ch[i];
} p = p->next[k];
} p->index = index;//注意,在此保证输入的模式串不反复,否则index会被覆盖
} void ACTree::NodeToQueue(Node *node, queue<Node*> &q)
{
if (node != nullptr)
{
for (int i = 0; i < MAX; i++)
{
if (node->next[i])
q.push(node->next[i]);//不知道这是干嘛的??想想BFS层次遍历的那些事
}
}
} void ACTree::BuildFailPointer()
{
queue<Node*> q; for (int i = 0; i < MAX; i++)
{
if (root->next[i])
{
NodeToQueue(root->next[i], q);//注意。切不可写成q.push(root->next[i]);
root->next[i]->fail = root;
}
} Node *parent, *p;
char ch;
while (!q.empty())
{
p = q.front();
ch = p->x;
parent = p->parent;
q.pop();
NodeToQueue(p, q); while (1)
{
if (parent->fail->next[ch - 'a'] != nullptr)
{
p->fail = parent->fail->next[ch - 'a'];
break;
}
else
{
if (parent->fail == root)
{
p->fail = root;
break;
}
else
parent = parent->fail->parent;
}
}
}
} void ACTree::ACSearch(const char *s)
{
int len = strlen(s);
if (len == 0) return; Node *p = root; int i = 0;
while (i < len)
{
int k = s[i] - 'a'; if (p->next[k] != nullptr)
{
p = p->next[k]; if (p->index != -1)
cout << i - strlen(pattern[p->index]) + 1 << "\t" << p->index << "\t" << pattern[p->index] << endl; i++;
}
else
{
if (p == root)
i++;
else
{
p = p->fail;
if (p->index != -1)
cout << i - strlen(pattern[p->index]) + 1 << "\t" << p->index << "\t" << pattern[p->index] << endl;
}
}
} while (p != root)
{
p = p->fail;
if(p->index!=-1)
cout << i - strlen(pattern[p->index]) + 1 << "\t" << p->index << "\t" << pattern[p->index] << endl;
}
}

四:数据測试

返回文件夹---->数据结构与算法文件夹

数据结构与算法系列----AC自己主动机的更多相关文章

  1. 字符串算法之 AC自己主动机

    近期一直在学习字符串之类的算法,感觉BF算法,尽管非常easy理解,可是easy超时,全部就想学习其它的一些字符串算法来提高一下,近期学习了一下AC自己主动机.尽管感觉有所收获,可是还是有些朦胧的感觉 ...

  2. HDU 2222 Keywords Search AC自己主动机入门题

    单词统计的题目,给出一些单词,统计有多少单词在一个文本中出现,最经典的入门题了. AC自己主动机的基础: 1 Trie. 以这个数据结构为基础的,只是添加一个fail指针和构造fail的函数 2 KM ...

  3. Keywords Search (ac 自己主动机)

    Keywords Search Problem Description In the modern time, Search engine came into the life of everybod ...

  4. AC自己主动机

    AC自己主动机 AC自己主动机是KMP和Trie的结合,主要处理多模板串匹配问题.以下推荐一个博客,有助于学习AC自己主动机. NOTONLYSUCCESS  这里另一个Kuangbin开的比赛,大家 ...

  5. 浩爷AC自己主动机高速学习方案

        今天弄完自己主动机之后.从那天比赛的阴影中爬出来了,猛地一看真不咋滴难,细致一看这尼玛还不如猛的一看. ..     必备算法:KMP,字典树(KMP我写了,字典树太简单,就是一个思想.我能够 ...

  6. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  7. POJ 2778 DNA Sequence (AC自己主动机 + dp)

    DNA Sequence 题意:DNA的序列由ACTG四个字母组成,如今给定m个不可行的序列.问随机构成的长度为n的序列中.有多少种序列是可行的(仅仅要包括一个不可行序列便不可行).个数非常大.对10 ...

  8. hdu 2222 Keywords Search ac自己主动机

    点击打开链接题目链接 Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  9. 【UVA】1449-Dominating Patterns(AC自己主动机)

    AC自己主动机的模板题.须要注意的是,对于每一个字符串,须要利用map将它映射到一个结点上,这样才干按顺序输出结果. 14360841 1449 option=com_onlinejudge& ...

随机推荐

  1. 基于 FPGA 的图像边缘检测

    本文主要内容是实现图像的边缘检测功能 目录 mif文件的制作 调用 ip 核生成rom以及在 questasim 仿真注意问题 灰度处理 均值滤波:重点是3*3 像素阵列的生成 sobel边缘检测 图 ...

  2. springmvc始终跳转至首页,不报404错误

    本篇博客特别补充:2017-3-4 9:42,经过分析和测试,本篇博客的解决方案只是碰巧,暂时的解决了问题.在后续的运行中,又出现了同样的毛病.经过日志跟踪,发现了端倪,下篇博客深入的剖析!本篇博客, ...

  3. iOS使用cookie

    // // ViewController.m // cookie // // Created by 谭启宏 on 16/3/4. // Copyright © 2016年 tqh. All right ...

  4. 第一个 spring Boot 应用通过Docker 来实现构建、运行、发布

    1. Docker 简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙 ...

  5. 【BZOJ2243】染色(树链剖分)

    题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由 ...

  6. net5:Theme主题样式的动态变换,在内容页content中操作影响模板页的操作

    原文发布时间为:2008-07-29 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  7. 应用defineProperty简单实现vue的双向数据绑定

    双向数据绑定简易版本如何应用defineProperty的getter setter 方法 有这样HTML片段 <input type="text" id="dem ...

  8. js-键盘回车搜索enter

    这个问题需求在移动版上经常用到. <div class="sousuo">        <input type="text" placeho ...

  9. CCCC L2-024 部落【并查集】

    https://www.patest.cn/contests/gplt/L2-024 首先在一行中输出这个社区的总人数.以及互不相交的部落的个数.随后对每一次查询,如果他们属于同一个部落,则在一行中输 ...

  10. hdu6217(数学)

    题意: 你需要输出在16进制下,π的第n位的数字 分析: 既然要求第n位的数字,我们不妨把原来的数字乘上$16^{n-1}$,我们要求的就是这个和式的小数部分的最高位 我们可以用double暴力求出小 ...