在模式匹配问题中,如果模板有很多个,KMP算法就不太适合了。因为每次查找一个模板。都要遍历整个文本串。可不可以只遍历一次文本串呢?可以,方法是把所有模板组成一个大的状态转移图(称为$Aho-Corasick$自动机,简称$AC$自动机),而不是每个模板各建一个状态转移图。注意到KMP的状态转移图是线性的字符串加上失配边组成的,不难想到AC自动机是Trie加上失配边组成的。

下图是$\{he,she,his,hers \}$的Trie。

下图是对应的Aho-Corasick自动机。

如果已经构造好AC自动机,匹配算法几乎和KMP是一样的,代码如下:

//在T中找模板
void find(const char* T)
{
int n = strlen(T);
int j = ; //当前结点编号,初始为根节点
for (int i = ; i < n; i++) //文本串当前指针
{
int c = idx(T[i]);
while (j && !ch[j][c]) j = f[j]; //顺着失配边走,直到可以匹配
j = ch[j][c];
if (val[j]) print(j);
else if (last[j]) print(last[j]); //找到了
}
}

其中print函数为:

//递归打印以结点j结尾的所有字符串
void print(int j)
{
if (j)
{
printf("%d: %d\n",j, val[j]);
print(last[j]);
}
}

代码中出现了一个陌生的数组last,下面解释以下。和Trie一样,我们认为所有val[j]>0的结点都是单词结点,反之亦然。但和Trie不同的是,同一个结点可能对应多个字符串的结尾,如图所示:

结点B不仅意味着找到串101,还意味着找到串01。换句话说,当找到一个模板后,应该顺着失配指针往回走,,看看有没有其它串。当然,失配指针不一定指向一个单词结点(比如,两个串是101和010,那么上图的结点A不是单词结点),为了提高效率,这里增设一个指针last[j],表示结点j沿着失配指针往回走时,遇到的下一个单词结点编号。这个last[j]在正规文献中叫后缀链接(suffix link)。

计算失配函数的方式和KMP很接近,只是把线性递归改成了按照BFS顺序递推,代码如下:

//计算fail函数
void getFail()
{
queue<int>q;
f[] = ;
//初始化队列
for (int c = ; c < sigma_size; c++)
{
int u = ch[][c];
if (u)
{
f[u] = ;
q.push(u);
last[u] = ;
}
}
//按BFS序计算fail
while (!q.empty())
{
int r = q.front(); q.pop();
for (int c = ; c < sigma_size; c++)
{
int u = ch[r][c];
if (!u) continue;
q.push(u);
int v = f[r];
while (v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = (val[f[u]] ? f[u] : last[f[u]]);
}
}
}

由于失配工程比较复杂,要反复沿着失配边走,在实践中常常会把上述AC自动机改造一下,把所有不存在的边补上,即把计算失配函数中的语句"if(!u)  continue;"改成:if(!u){ ch[r][c] = ch[f[r]][c]; continue;}

这样,就完全不需要失配函数了,而是对所有的转移一视同仁也就是说,find函数中的语句"while(j && !ch[j][c])  j=f[j];"; 可以直接完全删除。

Aho-Corasick自动机的更多相关文章

  1. 多模字符串匹配算法-Aho–Corasick

    背景 在做实际工作中,最简单也最常用的一种自然语言处理方法就是关键词匹配,例如我们要对n条文本进行过滤,那本身是一个过滤词表的,通常进行过滤的代码如下 for (String document : d ...

  2. Aho - Corasick string matching algorithm

    Aho - Corasick string matching algorithm 俗称:多模式匹配算法,它是对 Knuth - Morris - pratt algorithm (单模式匹配算法) 形 ...

  3. 中文分词系列(二) 基于双数组Tire树的AC自动机

    秉着能偷懒就偷懒的精神,关于AC自动机本来不想看的,但是HanLp的源码中用户自定义词典的识别是用的AC自动机实现的.唉-没办法,还是看看吧 AC自动机理论 Aho Corasick自动机,简称AC自 ...

  4. HanLP自然语言处理包介绍

    支持中文分词(N-最短路分词.CRF分词.索引分词.用户自定义词典.词性标注),命名实体识别(中国人名.音译人名.日本人名.地名.实体机构名识别),关键词提取,自动摘要,短语提取,拼音转换,简繁转换, ...

  5. 敏感词过滤的算法原理之 Aho-Corasick 算法

    参考文档 http://www.hankcs.com/program/algorithm/implementation-and-analysis-of-aho-corasick-algorithm-i ...

  6. HanLP自然语言处理包开源(包含源码)

    支持中文分词(N-最短路分词.CRF分词.索引分词.用户自定义词典.词性标注),命名实体识别(中国人名.音译人名.日本人名.地名.实体机构名识别),关键词提取,自动摘要,短语提取,拼音转换,简繁转换, ...

  7. Python分词工具——pyhanlp

    本文为本人学习pyhanlp的笔记,大多知识点来源于GitHubhttps://github.com/hankcs/HanLP/blob/master/README.md,文中的demo代码来源于该G ...

  8. AC 自动机

    AC自动机(Aho-Corasick Automata)是经典的多模式匹配算法.从前我学过这个算法,但理解的不深刻,现在已经十分不明了了.现在发觉自己对大部分算法的掌握都有问题,决定重写一系列博客把学 ...

  9. 算法 - DNA搜索 - Ako Corasick

    场景:从很长的字符串(输入字符串.DNA)中搜索大量固定字符串(字典.基因) 题目:Determining DNA Health | HackerRank 算法:Aho–Corasick algori ...

  10. Aho-Corasick算法、多模正则匹配、Snort入门学习

    希望解决的问题 . 在一些高流量.高IO的WAF中,是如何对规则库(POST.GET)中的字符串进行多正则匹配的,是单条轮询执行,还是多模式并发执行 . Snort是怎么组织.匹配高达上千条的正则规则 ...

随机推荐

  1. 程序员必备,C#各类项目、开源项目插件资料收藏

    一.AOP框架     Encase 是C#编写开发的为.NET平台提供的AOP框架.Encase独特的提供了把方面(aspects)部署到运行时代码,而其它AOP框架依赖配置文件的方式.这种部署方面 ...

  2. [poj]2488 A Knight's Journey dfs+路径打印

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 45941   Accepted: 15637 Description Bac ...

  3. 机器学习中的L1、L2正则化

    目录 1. 什么是正则化?正则化有什么作用? 1.1 什么是正则化? 1.2 正则化有什么作用? 2. L1,L2正则化? 2.1 L1.L2范数 2.2 监督学习中的L1.L2正则化 3. L1.L ...

  4. vue、React Nactive的区别(转载)

    Vue与React的对比 Vue.js与React.js从某些反面来说很相似,通过两个框架的学习,有时候对一些用法会有一点思考,为加深学习的思索,特翻阅了两个文档,从以下各方面进行了对比,加深了对这两 ...

  5. 判断iphone 屏幕大小宏定义

    #define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)  #define IS_IPHONE (UI_USER_I ...

  6. 初探 Nginx 架构

    转载自:http://wiki.jikexueyuan.com/project/nginx/nginx-framework.html Nginx 在启动后,在 unix 系统中会以 daemon 的方 ...

  7. 洛谷P2136 拉近距离

    题目背景 我是源点,你是终点.我们之间有负权环. --小明 题目描述 在小明和小红的生活中,有\(N\)个关键的节点.有\(M\)个事件,记为一个三元组\((S_i,T_i,W_i)\),表示从节点\ ...

  8. Python网络编程之基础

    计算机网络基础 网络到底是什么?计算机之间如何通信的? 早期:联机 以太网:局域网与交换机 ******广播 主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发, 所 ...

  9. render函数和redirect函数的区别+反向解析

    render函数和redirect函数的区别+反向解析 1.视图函数:一定是要包含两个对象的(render源码里面有HttpResponse对象)   request对象:----->所有的请求 ...

  10. 牛客假日团队赛2 F.跳跃

    链接: https://ac.nowcoder.com/acm/contest/924/F 题意: Farmer John为了满足奶牛对美的享受而安装了人工湖.矩形的人工湖分成M行N列(1 <= ...