AC自动机代码实现

Python实现AC自动机 文章目录前言原理简析代码实现后文 前言 下文的代码有些部分参考了这篇文章,但我仍然坚持作为原创而非转载,自有我的考虑。 在看下文之前,需要理解的基础知识有KMP算法原理和字典树数据结构理解。了解了上述内容就可以开始之后的旅程了。 原理简析 AC自动机相比于字典树结构仅仅是多了fail结点,指向其已匹配成功的前缀。其模式匹配与KMP算法一致。 引用百度百科的图片,即sh后匹配e失败,此时h其实是已经... 阅读详情

转载自http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。
     如果你对KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干什么用的。KMP中我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符,当A[i+1]≠B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配,而next函数恰恰记录了这个j应该调整到的位置。同样AC自动机的失败指针具有同样的功能,也就是说当我们的模式串在Tire上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。
      看下面这个例子:给定5个单词:say she shr he her,然后给定一个字符串yasherhs。问一共有多少单词在这个字符串中出现过。我们先规定一下AC自动机所需要的一些数据结构,方便接下去的编程。

有了这些数据结构之后,就可以开始编程了:
   
首先,将这5个单词构造成一棵Tire,如图-1所示。

 

 1  void  insert( char   * str,node  * root){ 
 2      node  * p = root; 
 3       int  i = 0 ,index;  
 4       while (str[i]){ 
 5          index = str[i] - ' a ' ; 
 6           if (p -> next[index] == NULL) p -> next[index] = new  node();  
 7          p = p -> next[index];
 8          i ++ ;
 9      } 
10      p -> count ++ ;      // 在单词的最后一个节点count+1,代表一个单词
11  }

在构造完这棵Tire之后,接下去的工作就是构造下失败指针。构造失败指针的过程概括起来就一句话:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。具体操作起来只需要:先把root加入队列(root的失败指针指向自己或者NULL),这以后我们每处理一个点,就把它的所有儿子加入队列,队列为空。

 1  void  build_ac_automation(node  * root){
 2     int  i;
 3      root -> fail = NULL; 
 4      q[head ++ ] = root; 
 5       while (head != tail){ 
 6          node  * temp = q[tail ++ ]; 
 7          node  * p = NULL; 
 8           for (i = 0 ;i < 26 ;i ++ ){ 
 9               if (temp -> next[i] != NULL){ 
10                   if (temp == root) temp -> next[i] -> fail = root;                 
11                   else { 
12                      p = temp -> fail; 
13                       while (p != NULL){  
14                           if (p -> next[i] != NULL){ 
15                              temp -> next[i] -> fail = p -> next[i]; 
16                               break ; 
17                          } 
18                          p = p -> fail; 
19                      } 
20                       if (p == NULL) temp -> next[i] -> fail = root; 
21                  } 
22                  q[head ++ ] = temp -> next[i];  
23              } 
24          }   
25      } 
26  }


    从代码观察下构造失败指针的流程:对照图-2来看,首先root的fail指针指向NULL,然后root入队,进入循环。第1次循环的时候,我们需要处理2个节点:root->next[‘h’-‘a’](节点h) 和 root->next[‘s’-‘a’](节点s)。把这2个节点的失败指针指向root,并且先后进入队列,失败指针的指向对应图-2中的(1),(2)两条虚线;第2次进入循环后,从队列中先弹出h,接下来p指向h节点的fail指针指向的节点,也就是root;进入第13行的循环后,p=p->fail也就是p=NULL,这时退出循环,并把节点e的fail指针指向root,对应图-2中的(3),然后节点e进入队列;第3次循环时,弹出的第一个节点a的操作与上一步操作的节点e相同,把a的fail指针指向root,对应图-2中的(4),并入队;第4次进入循环时,弹出节点h(图中左边那个),这时操作略有不同。在程序运行到14行时,由于p->next[i]!=NULL(root有h这个儿子节点,图中右边那个),这样便把左边那个h节点的失败指针指向右边那个root的儿子节点h,对应图-2中的(5),然后h入队。以此类推:在循环结束后,所有的失败指针就是图-2中的这种形式。


  最后,我们便可以在AC自动机上查找模式串中出现过哪些单词了。匹配过程分两种情况:(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。

 1  int  query(node  * root){ 
 2       int  i = 0 ,cnt = 0 ,index,len = strlen(str); 
 3      node  * p = root;  
 4       while (str[i]){  
 5          index = str[i] - ' a ' ;  
 6           while (p -> next[index] == NULL  &&  p != root) p = p -> fail; 
 7          p = p -> next[index]; 
 8          p = (p == NULL) ? root:p; 
 9          node  * temp = p; 
10           while (temp != root  &&  temp -> count !=- 1 ){ 
11              cnt += temp -> count; 
12              temp -> count =- 1 ; 
13              temp = temp -> fail; 
14          } 
15          i ++ ;                 
16      }    
17       return  cnt; 
18  }

    对照图-2,看一下模式匹配这个详细的流程,其中模式串为yasherhs。对于i=0,1。Trie中没有对应的路径,故不做任何操作;i=2,3,4时,指针p走到左下节点e。因为节点e的count信息为1,所以cnt+1,并且讲节点e的count值设置为-1,表示改单词已经出现过了,防止重复计数,最后temp指向e节点的失败指针所指向的节点继续查找,以此类推,最后temp指向root,退出while循环,这个过程中count增加了2。表示找到了2个单词she和he。当i=5时,程序进入第5行,p指向其失败指针的节点,也就是右边那个e节点,随后在第6行指向r节点,r节点的count值为1,从而count+1,循环直到temp指向root为止。最后i=6,7时,找不到任何匹配,匹配过程结束。

 1  const   int  kind  =   26 ; 
 2  struct  node{  
 3      node  * fail;        // 失败指针
 4      node  * next[kind];  // Tire每个节点的个子节点(最多个字母)
 5       int  count;         // 是否为该单词的最后一个节点
 6      node(){            // 构造函数初始化
 7          fail = NULL; 
 8          count = 0 ; 
 9          memset(next,NULL, sizeof (next)); 
10      } 
11  } * q[ 500001 ];           // 队列,方便用于bfs构造失败指针
12  char  keyword[ 51 ];      // 输入的单词
13  char  str[ 1000001 ];     // 模式串
14  int  head,tail;         // 队列的头尾指针

F28335 DSP ePWM模块实战:从基础配置到电机控制 本文详细解析了TI TMS320F28335 DSP的ePWM模块,从基础概念、寄存器配置到实战应用。通过代码示例,手把手教你如何配置定时中断、生成PWM波形、实现死区保护与故障联防,并最终完成一个可调速、可换向的直流电机控制项目,是掌握F28335电机控制核心技术的实战指南。 阅读详情

相关推荐

YOLOv8损失函数升级:从CIoU到Wise-IoU v3的实战调优与避坑指南

本文详细介绍了如何将YOLOv8的损失函数从CIoU升级到Wise-IoU v3,以提升目标检测性能,特别是在小目标检测和样本不均衡场景下的表现。通过实战调优步骤和避坑指南,帮助开发者有效应用Wise-IoU v3的动态聚焦机制和单调性控制,显著提升模型精度和训练稳定性。

weixin_33737774的博客 590

AC自动机 php代码实现

以下文字都为拷贝,懒,没有第二个原因! ac自动机很神奇,在于这个算法中失配指针的妙处(好比kmp算法中的next数组),说它高深,是因为这个不是一般的算法,而是建立在两个普通算法的基础之上,而这两个算法就是kmp与字典树。所以,如果在看之前,你还不会字典树或者kmp算法,那么请先学习字典树或者kmp算法之后再来看 理论请前往这里,反正很多都可以百度 kmp走起 trie树 数据结构 代码质量不高...

weixin_33877092的博客 698

52页PPT智慧矿山数字化工业大数据平台建设方案

致力于为煤炭企业构建“全”、“统”、“通”、”智”的(大数据平台/数据中台)体系,基于“数字新基建”时代的数据价值思考,构建全域数字化矿区共享能力中心,助力煤炭企业实现数字化转型,打通底层系统之间数据壁垒,加强公司整体管理和安全生产系数,为运营提供数据统筹模型,实现重点数据实时监控和数据共享开放服务。综上所述,智慧矿山数据治理是一个系统性的工程,需要煤炭企业内各部门连同行业和政府监管部门通力协作,制定数据标准和管理规范,重塑煤炭企业数据架构和数据传输链路,打通智慧矿山数据壁垒,保障数据质量和数据安全。

zuoan1993的博客 1055

ac自动机

下面开始用图学习ac自动机吧(个人比较喜欢放图,能用一张图解决的绝不叨叨) 首先给定模式串"ash","shex","bcd","sha",然后我们根据模式串建立如下trie树: 然后我们再了解下一步: ac自动机,就是在tire树的基础上,增加一个fail指针,如果当前点匹配失败,则将指针转移到fail指针指向的地方,这样就不用回溯,而可以路匹配下去了.(当前模式串后缀和fail指针指向的...

Insistor 714

从 0 到 1 构建 Graph RAG 系统:本地图谱 + 通义千问落地实践

本文介绍了一个基于知识图谱的检索增强生成系统(Graph RAG),该系统结合领域知识图谱、语义检索和大模型问答,旨在提供结构化、精准的技术问答服务。文章详细说明了项目背景、目标、核心技术架构以及实现方法,包括本地图谱构建、Neo4j数据库接入、语义检索和大模型集成等关键环节。该系统支持混合检索、多轮问答和知识图谱关联理解,能够有效减少大模型幻觉,提升问答的准确性和可解释性。文中还展示了核心代码结构和流程图,呈现了从文档加载到图谱构建再到问答生成的完整流程。该系统适用于需要处理复杂领域知识的研发和数据分析场

m0_58378112的博客 1399

2024最新版Anaconda Navigator安装使用指南

本文简要介绍如何下载安装Anaconda Navigator最新版,以及如何使用Python内核搭载来完成应用程序开发。

jackson_lingua的博客 1万+

AC自动机详解(转)

(转载自http://www.cppblog.com/mythit/archive/2009/04/21/80633.html)首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(

幻想の天地 737

多物理场耦合仿真-主题032-电磁-流体耦合

电磁-流体耦合,即磁流体动力学(MHD, Magnetohydrodynamics),是研究导电流体在电磁场中运动规律的学科,涉及电磁场与流体力学的深度耦合。本主题系统阐述磁流体动力学的基本理论、控制方程和数值方法。首先介绍MHD的基本概念和物理基础,包括导电流体的性质、电磁场基本方程;然后详细推导MHD控制方程组,包括连续性方程、动量方程、能量方程和电磁场方程;接着讨论MHD流动的特征参数,如Hartmann数、磁雷诺数、相互作用参数等;最后通过六个典型工程案例展示MHD分析的实际应用,包括电磁泵、磁流体

2401_87715305的博客 423

Leetcode每日一题:116.populating-next-right-pointers-in-each-node(填充每个节点的下一个右侧节点指针)

思路:对整个满二叉树进行层次遍历,同时把每一层的节点连起来now->next=q.front(),当到达该层最后一个结点时(len-1)时,令其指向NULL; /* // Definition for a Node. class Node { public: int val; Node* left; Node* right; Node* next; Node() : val(0), left(NULL), right(NULL), next(NULL) {.

CodeLuweir 的博客 325

Go语言爬虫:chromedp 的详细使用

chromedp 是 Go 语言中无头浏览器自动化的终极利器。它能驱动真实的 Chrome 浏览器,处理 JavaScript 渲染、复杂交互和反爬虫机制

数据知道的博客 4492

基于STM32+Qt上位机设计的智慧停车场管理系统(207)

本项目设计了一套基于STM32+Qt上位机的智慧停车场管理系统。该系统融合了先进的嵌入式技术、图像识别技术、数据库技术和移动互联网技术,通过STM32硬件端实时采集车库现场信息,包括车牌识别、车位占用状态监测等,并将数据上传至Qt上位机进行处理与展示。利用MySQL数据库存储车辆出入库记录及车位使用情况,确保数据的安全性和可追溯性;通过Android手机APP为用户提供查询、支付等功能,实现远程交互与便捷服务。

3941

AC自动机

在字典树上加上失配链(也可以叫做失败指针)就可以构成AC自动机,可以用来解决多模式匹配的问题。给定多个模式串P0、P1、……,给定目标串T,问T中包含了哪些P……等等问题。 在AC自动机中,每一个节点都有一个失败指针指向自动机中的另外一个节点;除了根节点,根节点的失败指针指向NULL。假设节点A的失败指针指向节点B,说明节点A的向上的字符串与从根到B的字符串匹配,而且匹配长度是最长的。 如下的A

RBS的专栏 937

BurpSuite工具HaE插件好用正则收集

数据集合面板里面直接查询捕获到的相关数据内容,省去一个个翻找数据包内容的烦恼。插件捕获到匹配正则表达式的数据包后,可以在。可以对正则条目进行添加、编辑、删除。规则信息管理,我们点击。

墨痕诉清风的博客 643

AC自动机原理及代码实现

AC自动机原理及代码实现

z1171127310的博客 933

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

详解 AC 自动机:从原理到代码实现

本文详细解析了AC自动机算法在多模式字符串匹配中的应用。该算法结合Trie树和KMP思想,通过构建Trie树存储模式串、设计失败指针实现快速跳转,能够在O(L+M+Z)时间复杂度内完成匹配。文章以洛谷模板题为例,完整展示了AC自动机的实现过程,包括Trie树构建、失败指针计算、文本匹配和拓扑排序累加结果等核心步骤。AC自动机通过路径压缩和层次遍历优化,显著提升了匹配效率,适用于信息检索、内容过滤等场景,是处理大规模字符串匹配问题的重要算法。

x3468714225的博客 1120

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

AC 自动机算法 JAVA代码 实现

AC自动机算法 1、简要概述 ​ 什么是AC自动机算法? ​ AC自动机算法是一种多模式字符串匹配算法,什么是多模式?从单模式说起,举个kmp算法的例子,单模式就是利用kmp算法验证某个敏感词在一个字符串内是否存在;多模式是说验证多个敏感词在一个字符串内是否存在。如果使用kmp来做的话,依次遍历多个敏感词,每个敏感词使用kmp验证,当敏感词数量很多的时候效率很低,这时候就用到AC自动机算法了。 ​ 为什么AC自动机算法效率高? ​ 结论:其能在约为O(n) 的时间复杂度内完成对多个敏感词的查找,而且

dream_coke的博客 3467

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

AC自动机详解,原理、优化分析,代码实现

填坑ing

EQUINOX1的博客 9484

AC自动机算法详解以及Java代码实现

详细介绍了AC自动机算法详解以及Java代码实现。

终生学习践行者 3507

AC自动机完整代码——数组实现,非指针

#include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; struct trie{ int next[500010][26],fail[500010],end[500010]; int root,L; int newnode() { for(int i=0;i<

Maybemust的博客 778

高性能AC自动机:基于TrieTree的优化与实现(C/C++代码实现)

基于 STL map、unordered_map 和 skiplist 的 TrieTree 在 AC 自动机中的应用具有重要的理论和实践意义。通过合理选择和使用 STL 容器,可以高效地构建和操作 TrieTree,从而实现 AC 自动机的快速多模匹配功能。在文本编辑、网络内容过滤、信息检索、自然语言处理、网络安全防护等多个领域,AC 自动机结合基于 STL 容器的 TrieTree 都展现出了显著的优势,能够提高系统的性能、灵活性和可扩展性,为解决复杂的文本匹配问题提供了有力的工具和方法。

chen1415886044的博客 1215

零基础理解AC自动机:图文详解+代码实现

简单来说,AC自动机是Trie树和KMP算法的结合体。它能同时匹配多个关键词,就像搜索引擎里输入几个词瞬间找到所有结果一样高效。核心优势在于预处理阶段构建的失效指针,让匹配失败时能智能跳转。

GoldenleafRaven13的博客 764

算法导论—AC自动机

华电北风吹 日期:2016-05-03AC自动机是比较高效的多模式匹配算法。类似于KMP在模式串上的状态转移算法,AC自动机通过在trie树上建立状态转移,使得对匹配串遍历一遍就可以找到所有的模式串。 AC自动机一般有以下三步:首先,对所有的模式串建立trie树。然后,对trie树所有节点以它的最长后缀对应的前缀字符串作为它的失配指针,建立AC自动机。最后一步,对文本串在AC自动机上进行匹配。参

掉下个小石头 1645

AC自动机 hdu2222 Keywords Search

传送门:点击打开链接 题意:给一个字典,再给一个查询串,问字典中的单词一共在这个查询串中出现了多少次。 思路:裸AC自动机。。第一次做,照着bin神代码写了个模板留着以后贴 #include #include #include #include #include #include #include #include #include #include #include #include #i

qwb的博客 852

【小结】AC自动机

参考资料:http://blog.csdn.net/niushuai666/article/details/7002823 搞了两天,突然明白,这玩意它原来就是个DFADFA鸭!窝来分析分析 从DFADFA到ACAC自动机: 考虑以下单词: {she, he, her}\{she,\ he,\ her\},字母表∑\sum为2626个小写字母 我们先画出它Trie树的模样 注意,双圈的是包含单词结尾

When you go away 806
上一篇: (字典树+AC自动机) hdu 2222 Keywords Search
下一篇: (最短路 + 枚举) poj 1062 昂贵的聘礼
Hashmat
博客等级 码龄16年 14粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值