关于 AC 自动机

什么是 AC 自动机

AC 自动机,全称 Aho-Corasick 自动机,是一种用于字符串搜索的算法,由 Alfred V. Aho 和 Margaret J. Corasick 在 1975 年提出。这个算法是为了解决在一个主文本字符串中查找多个模式字符串(或称为“关键词”)的问题,它可以在线性时间内完成搜索,非常高效。

下文是 wiki 百科中的原文内容

在计算机科学中,Aho-Corasick 算法是 Alfred V. Aho 和 Margaret J. Corasick 于 1975 年发明的一种字符串搜索算法。 [1]它是一种字典匹配算法,用于在输入文本中定位有限字符串集(“字典”)的元素。它同时匹配所有字符串。算法的复杂度与字符串的长度加上搜索文本的长度加上输出匹配的数量呈线性关系。请注意,由于找到了所有匹配项,因此如果每个子字符串都匹配,则匹配项的数量可能是二次方(例如,dictionary = a、aa、aaa、aaaa 和 input 字符串是aaaa)。

通俗地说,该算法构建了一个类似于特里树的有限状态机,在各个内部节点之间具有附加链接。这些额外的内部链接允许在失败的字符串匹配之间快速转换(例如,在不包含 cart 的 trie 中搜索 cart,但包含 art,因此会在以 car 为前缀的节点处失败)到共享的 trie 的其他分支通用后缀(例如,在前面的情况下,属性分支可能是最好的横向转换)。这允许自动机在字符串匹配之间转换,而不需要回溯。

当预先知道字符串字典(例如计算机病毒数据库)时,可以离线执行自动机的构造,并将编译后的自动机存储起来供以后使用。在这种情况下,其运行时间与输入长度加上匹配条目的数量成线性关系。Aho-Corasick 字符串匹配算法构成了原始 Unix 命令 fgrep 的基础。

In computer science, the Aho—Corasick algorithm is a string-searching
algorithm invented by Alfred V. Aho and Margaret J. Corasick in
1975.[1] It is a kind of dictionary-matching algorithm that locates elements of a finite set of strings (the “dictionary”) within an input
text. It matches all strings simultaneously. The complexity of the
algorithm is linear in the length of the strings plus the length of
the searched text plus the number of output matches. Note that because all matches are found, there can be a quadratic number of matches if every substring matches (e.g. dictionary = a, aa, aaa, aaaa and input string is aaaa).

Informally, the algorithm constructs a finite-state machine that
resembles a trie with additional links between the various internal
nodes. These extra internal links allow fast transitions between
failed string matches (e.g. a search for cart in a trie that does not
contain cart, but contains art, and thus would fail at the node
prefixed by car), to other branches of the trie that share a common
suffix (e.g., in the previous case, a branch for attribute might be
the best lateral transition). This allows the automaton to transition
between string matches without the need for backtracking.

When the string dictionary is known in advance (e.g. a computer virus
database), the construction of the automaton can be performed once
off-line and the compiled automaton stored for later use. In this
case, its run time is linear in the length of the input plus the
number of matched entries.

The Aho—Corasick string-matching algorithm formed the basis of the
original Unix command fgrep.

如何被想出来的呢?

Aho 和 Corasick 设计这个算法的初衷是为了提高字符串匹配的效率,特别是在需要同时查找多个模式字符串时。当时的背景是计算机科学正在迅速发展,人们需要更高效的算法来处理大量的文本数据。AC 自动机的设计灵感部分来自于有限状态机(Finite State Machine, FSM)和 Trie(字典树)的概念,通过将多个模式字符串构建成一个具有状态转移功能的 Trie 树,并在此基础上添加失败指针(fail pointer),使得在匹配失败时能够高效地转移到下一个可能的状态,从而避免了重复的匹配工作。

适用的场景

AC 自动机的主要应用场景包括:

  • 文本过滤和内容审查: AC 自动机可以用来在文本中查找敏感词或特定的词组,因此在内容审查和敏感信息过滤的系统中非常实用。
  • 生物信息学: 在基因序列分析中,可能需要在 DNA 序列中查找多个短序列,AC 自动机因其高效性而被广泛应用。
  • 网络安全: 在网络入侵检测系统(IDS)中,AC 自动机可用于匹配多种入侵签名或恶意代码片段。
  • 文本挖掘和自然语言处理: 在大规模文本数据中查找多个关键词或短语时,AC 自动机可以提供高效的解决方案。
  • 编译原理: 在词法分析阶段,AC 自动机可用于高效识别多个关键字和模式字符串。

原理之前的扩展

何为 Trie 树

Trie树(发音为"try"),又称为前缀树或字典树,是一种树形结构,它是一种用于快速检索字符串数据集中特定字符串的高效数据结构。

Trie树的基本概念和特点:

节点结构:Trie树的每个节点通常包含多个子节点,每个子节点代表一个字符。从根节点到某一节点的路径,代表一串字符。

  • 前缀共享:在Trie树中,具有共同前缀的字符串会共享前缀的路径。例如,字符串"tree"和"trie"会在前两个字符"tr"后分叉成两条路径。
  • 结束标记:为了标识一个字符串完整地出现在Trie树中,会在字符串的最后一个字符对应的节点上做一个特殊标记,如设置一个布尔标记或存储一个指向数据的引用。
  • 快速查找:使用Trie树可以在O(m)时间内查找一个长度为m的字符串,这是因为它几乎不涉及字符串比较操作。

Trie树的构建过程:

初始化: 从一个根节点开始,根节点通常不包含字符。
插入字符串: 将每个字符串的字符逐个插入到Trie树中。如果某个字符对应的节点不存在,则创建它。
重复字符: 如果插入的字符在Trie树中已有对应的节点,则沿着该节点继续插入下一个字符。
结束标记: 每个字符串的末尾字符对应的节点被标记为结束节点,表明一个字符串已经插入完成。

Trie树的应用场景:

词频统计:统计大量文本中单词的出现次数。
自动补全:搜索引擎中的自动补全功能。
拼写检查:检查单词的拼写是否正确。
字符串检索:在一组字符串中快速检索出包含特定前缀的所有字符串。

Trie树由于其高效的查找性能,特别适合于处理字符串匹配相关的问题。

何为自动机

“自动机”(Automaton)在计算机科学中通常指的是一种抽象的机器,它能够根据输入自动执行一系列操作,而不需要外部的干预。自动机通常根据一组规则或算法自动处理输入序列,并根据这些输入改变其内部状态,可能还会生成输出。它们在形式语言理论、编译器设计、文本处理等领域中有着广泛的应用。

Aho-Corasick自动机是一种特定类型的自动机,它根据一组预定义的字符串(模式)进行构建,当文本输入流被送入自动机进行处理时,AC自动机会自动地匹配这些预定义的模式。它之所以被称为自动机,是因为它能自动完成以下操作:

状态转换: AC自动机有一系列内部状态,这些状态对应于Trie树中的节点。每读取输入文本中的一个字符,自动机就根据当前状态和输入字符转移到下一个状态。

模式识别: 当输入文本中的某个部分与某个预定义的模式匹配时,AC自动机会识别出这个匹配,并可以执行相关的动作(例如,返回匹配位置、记录匹配等)。

失败转移: 如果当前状态没有一个直接的转移对应于当前的输入字符,自动机会使用失败指针(fail pointer)来找到下一个可能的状态,而不是从头开始匹配。

输出结果: 每当AC自动机到达某个状态,它会检查该状态是否对应于某个(或某些)预定义模式的结束。如果是,自动机将输出与当前状态相对应的模式的匹配信息。这些信息可能包括模式的起始索引、结束索引或是已匹配的文本部分。

因此,"自动机"这个名词强调了AC自动机在不需要人工干预的情况下对模式进行高效匹配的能力。自动机在遇到失败匹配时不需要回溯输入文本,而是能够利用内部的失败指针自动地跳转到其他可能的匹配状态,这是它与简单的模式匹配算法相比的一个显著优势。这种自动的状态转移和匹配检测过程是它得名"自动机"的原因。

Trie 树与 AC 自动机的联系

Trie 树,又称前缀树或字典树,是一种用于快速检索字符串数据集中的键的有序树结构。这种数据结构允许共享前缀,可以非常高效地存储和检索字符串集合中的关键字。Trie 树的每个节点代表一个字符串(或者字符串的一部分),每条边代表一个字符。从根节点到某一节点的路径对应于字典中的一个单词或者单词的前缀。

对于 Aho-Corasick 自动机,它确实是基于 Trie 树的,并在其上添加了失败指针来实现快速的模式匹配。如果你需要向 AC 自动机中添加新的元素,确实可能需要对树进行一定的更新或重建,尤其是更新失败指针。在实际应用中,如果频繁地添加新元素,这种重建可能会变得耗时。

AC 自动机本身就是一种特殊的数据结构,它结合了 Trie 树和状态机的特点。如果你要谈论这种结构并强调其用于模式匹配的特性,通常就会称之为 Aho-Corasick 自动机,简称 AC 自动机。在文献中,它没有一个不同的专用名称,通常就是直接称为 Aho-Corasick 自动机或者 AC 自动机。

在某些实现中,为了避免重建整个数据结构,可能会采用更灵活的数据结构,或者在 AC 自动机的基础上进行改进,使其支持动态插入和删除操作,但这通常会增加实现的复杂性。在需要处理动态变化的模式集合时,这些改进可能会提供更好的性能。

AC 自动机的原理

AC 自动机(Aho-Corasick 算法)是一种用于在输入文本中快速查找多个模式(即字符串)出现的算法。它由 Alfred V. Aho 和 Margaret J. Corasick 在 1975 年提出,主要用于字符串匹配问题,特别是在处理大量模式匹配时非常有效。AC 自动机的核心思想是将所有模式构建成一个有限状态机(Trie 树结构),并在这个结构中加入失败指针(fail pointer),使得在匹配失败时能快速转移到下一个可能的状态,从而避免重复检查之前已经匹配过的文本。

AC 自动机的构建过程

构建 AC 自动机的过程主要分为两个步骤:构建 Trie 树添加失败指针

构建 Trie 树:

  • 首先,将所有模式串构建成 Trie 树。每个节点代表一个字符,从根节点到某一节点的路径代表一个模式串的前缀。
  • 每个模式串的终点节点标记为输出,表示该路径对应的模式串已完全匹配。

添加失败指针:

  • 对于 Trie 树的根节点的所有直接子节点,它们的失败指针都指向根节点。
  • 对于其他节点,假设当前节点标记为字符 C,其父节点的失败指针指向的节点有一个直接子节点也标记为字符 C,则当前节点的失败指针指向那个子节点。如果找不到,就递归地沿着失败指针继续查找,直到到达根节点。

工作原理

在文本匹配阶段,AC 自动机从根节点开始,按照文本字符逐个进行转移,如果遇到匹配失败的情况,就通过失败指针跳转到其他分支继续匹配,这样可以避免从头开始匹配,提高效率。当到达某个节点时,如果该节点是输出节点,或者沿着失败指针可以回溯到一个输出节点,那么就找到了一个模式串的匹配。

用例举例

假设我们有一段文本 “abccab”,我们需要在这段文本中查找以下模式串:“a”, “ab”, “bc”, “bca”, “c” 和 “caa”。

构建 Trie 树: 首先基于这些模式串构建 Trie 树。
添加失败指针: 然后为 Trie 树中的每个节点添加失败指针。
文本匹配: 最后,使用 Trie 树来匹配整段文本。

在这个例子中,每个节点除了有指向子节点的指针外,还有一个失败指针(用虚线表示)。例如,节点 “b” 的失败指针指向根节点,因为当在 “ab” 后面遇到非 “c” 的字符时,下一个可能的匹配是从头开始的 “a”。

通过这种方式,AC 自动机可以在 O(n) 的时间复杂度内完成对所有模式串的匹配,其中 n 是文本的长度。这使得 AC 自动机在诸如网络内容过滤、生物信息学序列分析、文本编辑器的查找替换等场景中非常有用。

视频解释

可以结合上文的文字描述加上简单直观的视频解释,就可以很轻松的弄明白 AC 自动机的原理了。
用最直观的方式解释 AC 自动机

实际用例举例

此图是维基百科中举例的图片。我们对此张图片涉及到的构建、添加失败指针、文本匹配来一一做对应的解释。
在这里插入图片描述
构建Trie树(黑色"子节点"弧线):

从根节点开始,为字典中的每个单词构建一条路径。这些黑色弧线代表从一个节点通过添加一个字符到达另一个节点的转移。例如,从根节点到节点"a",然后到节点"ab",这样为单词"ab"在Trie树中建立一条路径。
如果一个节点代表字典中的一个完整单词,那么这个节点是白色的。如果它不代表一个完整的单词,只是单词的一个前缀,那么它是灰色的。

添加失败指针(蓝色"后缀"弧线):

对于图中的每个节点,都有一个指向它的最长可能严格后缀的节点的蓝色弧线。“严格后缀"意味着除了节点本身之外的后缀。例如,对于节点"caa”,它的严格后缀是"aa"、“a"以及根节点(空字符串),而图中存在的最长后缀是"a”,因此有一条从"caa"到"a"的蓝色弧线。

这些蓝色弧线能够通过广度优先搜索计算得出,当访问到一个节点时,可以通过跟随其父节点的蓝色弧线来找到它的最长后缀节点,并检查该后缀节点的子节点中是否有与当前节点匹配的字符。如果没有匹配,则继续跟随蓝色弧线寻找下一个最长后缀,直到找到匹配或到达根节点。

添加绿色"字典后缀"弧线:

绿色弧线从每个节点出发,直接指向通过蓝色弧线能够到达的下一个字典中的单词节点。例如,从节点"bca"出发,跟随蓝色弧线可以先到"ca",再到"a",而"a"是字典中的一个单词,所以从"bca"到"a"有一条绿色的弧线。

这些绿色弧线可以通过从每个节点出发,沿着蓝色弧线重复遍历,直到找到一个代表字典中单词的节点(蓝色节点)计算得出,并且可以记忆这个信息以便快速查找。

文本匹配过程:

当使用AC自动机进行文本匹配时,会从根节点开始,针对输入文本中的每个字符进行状态转换。

如果当前节点有一个对应当前字符的子节点,就沿着黑色的子节点弧线进行转换。

如果没有对应的子节点,就沿着蓝色的后缀弧线转移到另一个状态,这个状态是当前节点所有可能后缀中最长的一个存在于Trie树中的状态。
在每次状态转换时,都会检查当前节点是否是一个蓝色节点(即字典中的单词),或者通过绿色的字典后缀弧线是否可以到达一个蓝色节点。如果是,那么就找到了一个匹配。

通过这种方式,AC自动机能够在文本中高效地找到所有字典中的单词,时间复杂度是线性的,即与文本的长度成正比。这使得AC自动机在诸如文本搜索、网络内容过滤和生物信息学等领域的字符串匹配问题中非常有用。

如果大家有兴趣的话不妨看看各语言 AC 自动机的视线源码,可以理解的更为透彻一点

源码实现

Java 版 AC 自动机
go 版 AC 自动机
其他

引用

用最直观的方式解释 AC 自动机
Aho–Corasick algorithm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400880.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IOT-Reaserch安装ghidra以及IDEA和ghidra的配置

Linux research 5.4.0-91-generic #102~18.04.1-Ubuntu SMP Thu Nov 11 14:46:36 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux java --version IOT自带的java是符合要求的,不需要额外下载 iotresearch:~/install-file$ java --version openjdk 11.0.13 2021-10-19 …

linux platform架构下I2C接口驱动开发

目录 概述 1 认识I2C协议 1.1 初识I2C 1.2 I2C物理层 1.3 I2C协议分析 1.3.1 Start、Stop、ACK 信号 1.3.2 I2C协议的操作流程 1.3.3 操作I2C注意的问题 2 linux platform驱动开发 2.1 更新设备树 2.1.1 添加驱动节点 2.1.2 编译.dts 2.1.3 更新板卡中的.dtb 2.2 …

观察者模式, 发布-订阅模式, 监听器模式

观察者模式, 发布-订阅模式, 监听器模式 观察者模式 观察者模式是一种行为型设计模式, 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 角色模型和结构图 在观察者模式中,只有两种…

⭐北邮复试刷题LCR 018. 验证回文串__双指针 (力扣119经典题变种挑战)

LCR 018. 验证回文串 给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。 本题中,将空字符串定义为有效的 回文串 。 示例 1: 输入: s “A man, a plan, a canal: Panama” 输出: true 解释…

【PX4SimulinkGazebo联合仿真】在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化

在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化 系统架构Matlab官方例程Control a Simulated UAV Using ROS 2 and PX4 Bridge运行所需的环境配置PX4&Simulink&Gazebo联合仿真实现方法建立Simulink模型并完成基本配置整体框架各子系统实现原理…

【Vuforia+Unity】AR05-实物3D模型识别功能实现

对于3D物体的识别,可以是虚拟的也可以是实物的,但是对于虚拟的三维模型意义不大,我们完全可以把三维模型放在屏幕上截一张图,以图片识别的方式召唤数字内容,不过在虚拟现实中或许有用。 因此本文探讨的技术路线主要是…

Docker之查看并获取最新Ubuntu镜像(十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

【快速搞定Webpack5】修改输出文件目录及自动清理上次打包文件(五)

介绍 默认情况下webpack打包后,我们的图片和js等文件都会被打包到dist目录下,文件多了混淆在一起一方面不利于文件的查找和管理,另外一方面看上去也不美观。 所以今天我们学习的内容就是控制输出后的文件进入不同的目录。 一、配置 新增4…

Nginx配置组成与性能调优

目录 一、Nginx配置介绍 1. 模块组成 2. 图示 3. 相关框架 二. 配置调优 1. 全局配置 1.1 关闭版本和修改版本 1.2 修改启动的进程数 1.3 cpu与work进程绑定 1.4 pid路径 1.5 nginx进程的优先级(work进程的优先级) 1.6 调试work进程打开的文…

npm run dev和npm run serve两个命令的区别

npm run dev和npm run serve两个命令的区别 前端开发过程中运行Vue项目的时候,有时候使用npm run serve命令可以启动项目,有时候却会报错;有时候使用npm run dev命令可以启动项目,有时候却也会报错。是什么原因造成这种情况呢&am…

问题:Spark SQL 读不到 Flink 写入 Hudi 表的新数据,打开新 Session 才可见

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

4、电源管理入门之子系统reset

目录 1. 简介 2. consumer-驱动软件 3. provider-reset驱动 3.1 整体介绍 3.2 reset复位API说明 之前的文章电源管理入门-1关机重启详解介绍了整机SoC的重启也可以说是reset,那么子系统的reset,例如某个驱动(网卡、USB等)或者某个子系统(NPU、ISP等运行在独立的M核或…

5、电源管理入门之 arm-scmi和mailbox核间通信

目录 1. 整体架构介绍 2 Linux中reset模块 2.1 Reset consumer 2.2 Reset provider 3. Linux SCMI reset通信 3.1 SCMI reset协议初始化 3.2 SCMI reset消息收发 4. SCP中reset 4.1 固件新增module 4.2 scmi_reset_domain初始化 4.3 scmi_reset_domain消息处理 4.3…

排序算法1:冒泡排序、快速排序、插入排序

排序算法&#xff1a;交换类排序&#xff0c;插入类排序、选择类排序、归并类排序 交换类排序&#xff1a;冒泡排序、快速排序 一、冒泡排序 #include <stdio.h> #include <stdlib.h> #include <time.h> typedef int ElemType; typedef struct{ElemType *e…

linux CentOs 安装docker 推荐生产环境使用

目录 1. 在CentOs上安装docker所需的系统环境 2. 卸载旧版本 2.1 查看是否已安装docker 2.2 卸载已安装的docker 3. 安装方式 3.1 使用rpm存储库安装(推荐使用该方法) 3.2 从包中安装 4. 开始docker 1. 在CentOs上安装docker所需的系统环境 需要以下CentOS版本之一的维…

压缩感知的图像仿真(MATLAB源代码)

压缩感知是一种用于高效获取和表示信号的技术&#xff0c;它可以显著减少数据的采样和传输量&#xff0c;同时保持对信号的高质量恢复能力。在压缩感知中&#xff0c;信号被表示为其在一个稀疏基中的稀疏线性组合。通过仅使用少量的随机投影测量&#xff0c;就能够捕捉信号的大…

Vue状态管理库-Pinia

一、Pinia是什么&#xff1f; Pinia 是 Vue 的专属状态管理库&#xff0c;它允许支持跨组件或页面共享状态&#xff0c;即共享数据&#xff0c;他的初始设计目的是设计一个支持组合式API的 Vue 状态管理库&#xff08;因为vue3一个很大的改变就是组合式API&#xff09;,当然这…

【数学建模入门】

数学建模入门 数学建模需要的学科知识怎么学习数学模型如何读好一篇优秀论文数学建模赛题常见类别数学建模常见问题数学建模组队和分工数学建模准备工作 数学建模需要的学科知识 怎么学习数学模型 &#x1f4a6;推荐阅读书籍&#xff1a; 《数学建模算法与应用》&#xff0c;…

tensorboard的用法

部分测试代码&#xff1a; from torch.utils.tensorboard import SummaryWriter import numpy as np from PIL import Image import torch import cv2 as cv import matplotlib.pyplot as plt from torch import nn from torchvision import datasetsdef functiontools():writ…

ros自定义action记录

文章目录 自定义action1. 定义action文件2. 修改 package.xml3. 修改 CMakeLists.txt4. 运行 catkin build4. simple_action_server.py5. simple_action_client.py 测试 自定义action ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.t…