java编程之AC自动机工作原理与实现代码

Java编程之AC自动机工作原理与实现代码

简介

AC自动机(Aho–Corasick automaton)是一种高效的多模式匹配算法。它能够同时对多个模式串进行匹配,并且时间复杂度是线性级别的。在字符串匹配、敏感词过滤、关键字过滤等领域广泛应用。本文将详细讲解AC自动机的工作原理以及在Java中实现AC自动机的代码。

工作原理

AC自动机的本质是构建了一个基于Trie树的有限状态自动机(FSM,finite-state machine)。它本质上是一个有向无环图,其每一个节点代表着一个模式串的前缀,边表示从该状态到其他状态的转移,边上的字符表示从该状态到下一个状态所需要的字符。图中有两种不同类型的节点,根节点和其他节点。

AC自动机的构建主要分为两个步骤:Trie树的构建和自动机转移表的加速构建。

Trie树的构建

前面已经提到了AC自动机的本质是一个基于Trie树的有限状态自动机,我们需要先构建Trie树。对于n个模式串S1,S2,S3,……,Sn,Trie树的构建方法如下:

  1. 取第一个模式串S1的第一个字符,作为根节点,增加一条从根节点指向该节点的边。
  2. 如果该节点对应的字符在S1中不是最后一个字符,则添加一条指向下一字符的边。在该节点处打上S1的下一字符的标记。否则,标记该节点并转到第3步。
  3. 取下一个模式串S2,从根节点开始,逐一匹配S1的字符,匹配成功则沿着其指向的边前进,否则将该字符作为一个新的节点加入到Trie树中,并添加从当前节点到该节点的一条边。重复该步骤直到S2匹配完成。
  4. 继续取下一个模式串,重复步骤3直到n个模式串全部匹配完成。

构建完Trie树之后,怎样找出所有的模式串呢?可以进行深度优先搜索(DFS)。从Trie树的根节点开始出发,到达第节点时,如果该节点已经被标记,就说明到达了一个单词的结尾,输出该单词。

自动机转移表的加速构建

在Trie树的基础上,还需要对AC自动机进行加速构建。对于每一个节点,我们可以通过增加注释或通过其他方式来标记它所代表的字符串在Trie树中的位置。然后,从根节点开始,对每个节点进行BFS遍历,计算出其后继节点。对于当前节点,利用其父节点的后继节点构造其自己的后继节点,如果无法匹配,则不断向上爬到父节点,找到下一个匹配的节点。这样生成的就是AC自动机的转移表。

AC自动机的Java实现

在Java中实现AC自动机,需要首先实现Trie树。可以通过一个TrieNode类来存储每个节点。

class TrieNode {
    Map<Character, TrieNode> children;
    boolean isEndOfWord;

    TrieNode() {
        children = new HashMap<>();
        isEndOfWord = false;
    }
}

然后,利用Trie树来构建AC自动机。可以通过增加注释或通过其他方式来标记每个节点所代表的字符串在Trie树中的位置,然后,从根节点开始,对每个节点进行BFS遍历,计算出其后继节点。对于当前节点,利用其父节点的后继节点构造其自己的后继节点,如果无法匹配,则不断向上爬到父节点,找到下一个匹配的节点。

class AC {
    TrieNode root;

    private void insert(TrieNode root, String word) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            node.children.putIfAbsent(c, new TrieNode());
            node = node.children.get(c);
        }
        node.isEndOfWord = true;
    }

    public void build(List<String> words) {
        root = new TrieNode();
        for (String word : words) {
            insert(root, word);
        }

        Queue<TrieNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TrieNode node = queue.poll();

            for (Map.Entry<Character, TrieNode> entry : node.children.entrySet()) {
                TrieNode child = entry.getValue();
                char c = entry.getKey();

                // Initialize fail state of this child
                while (node != root && !node.children.containsKey(c)) {
                    node = node.failState;
                }

                if (node.children.containsKey(c)) {
                    child.failState = node.children.get(c);
                } else {
                    child.failState = root;
                }

                queue.add(child);
            }
        }
    }
}

示例

public static void main(String[] args) {
    List<String> words = Arrays.asList("he", "she", "his", "hers");
    String text = "ushers";

    AC ac = new AC();
    ac.build(words);

    Set<String> matched = ac.match(text);
    System.out.println(matched);
}

对于输入文本"ushers",输出结果为["she", "he", "hers"]。

public static void main(String[] args) {
    List<String> words = Arrays.asList("program", "cram", "suffix", "ample");
    String text = "programmer";

    AC ac = new AC();
    ac.build(words);

    Set<String> matched = ac.match(text);
    System.out.println(matched);
}

对于输入文本"programmer",输出结果为["program", "cram", "ample"]。

总结

本文讲解了AC自动机的工作原理及其Java代码实现。AC自动机能够高效地处理多模式串匹配的问题,其应用广泛,特别是在字符串匹配、关键字过滤、敏感词过滤等领域。AC自动机虽然比较复杂,但是只要掌握了它的基本原理,就可以快速地实现AC自动机的代码,具有很广泛的应用前景。

阅读剩余 65%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java编程之AC自动机工作原理与实现代码 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • javaweb 国际化:DateFormat,NumberFormat,MessageFormat,ResourceBundle的使用

    一、概述在国际化应用中,日期格式化、数字格式化和消息格式化是常见的需求,针对这些需求,Java提供了一系列的类和工具:DateFormat、NumberFormat、MessageFormat和ResourceBundle。 二、DateFormat使用DateFormat是一个日期格式化类,它可以将Date对象格式化成指定的字符串。 使用方法如下: Dat…

    Java 2023年6月15日
    00
  • Spring4整合Hibernate5详细步骤

    下面是“Spring4整合Hibernate5详细步骤”的攻略,分别针对Spring和Hibernate进行详细讲解。 Spring配置 在pom.xml文件中添加Spring和Hibernate的依赖: <dependency> <groupId>org.springframework</groupId> <art…

    Java 2023年5月19日
    00
  • 在idea中显示springboot面板的方法

    在IDEA中,我们可以使用Spring Boot面板来管理Spring Boot应用程序。本文将详细讲解在IDEA中显示Spring Boot面板的方法的完整攻略,并提供两个示例。 1. 配置Spring Boot插件 以下是配置Spring Boot插件的基本流程: 打开IDEA,点击File -> Settings -> Plugins。 在…

    Java 2023年5月15日
    00
  • java使用反射给对象属性赋值的两种方法

    当我们需要在运行时使用Java代码来处理类,或者动态地访问和修改类的成员时,反射成为一种非常重要的机制。其中一个反射的应用场景就是给对象属性赋值,在此介绍两种方法。 方法一:使用Class类的getMethod()和setAccessible()方法 首先,需要获得指定的方法,然后再反射到对象上进行调用。下面是一个示例,通过这种方法动态设置User对象的na…

    Java 2023年5月26日
    00
  • 如何使用​win10内置的linux系统启动spring-boot项目

    下面是如何使用Win10内置的Linux系统启动spring-boot项目的完整攻略。 安装WSL WSL(Windows Subsystem for Linux)是Win10内置的Linux子系统,可在其上运行各种Linux发行版。要使用WSL启动spring-boot项目,首先需要安装WSL: 打开”控制面板”,进入”程序与功能”,选择左侧的”启用或关闭…

    Java 2023年5月19日
    00
  • 浅谈java日志格式化

    浅谈Java日志格式化 什么是日志格式化 在进行Java应用开发的过程中,日志系统是必不可少的一个组件。日志格式化就是在记录应用程序运行中产生的日志信息时,对不同的信息类型进行分类、分级,并为每一条日志信息提供一个易于读取和理解的格式,以方便后续的调试、运维和分析工作。 日志格式化的重要性 在一个应用程序中,日志系统是一个非常重要的组件。通过日志系统,可以帮…

    Java 2023年5月26日
    00
  • springMVC配置环境实现文件上传和下载

    SpringMVC配置环境实现文件上传和下载的完整攻略 SpringMVC是一种基于Java的Web框架,它可以帮助我们快速开发Web应用程序。在SpringMVC中,我们可以使用MultipartResolver来实现文件上传,使用ResponseEntity来实现文件下载。本文将介绍如何配置SpringMVC环境,实现文件上传和下载,并提供两个示例说明。…

    Java 2023年5月17日
    00
  • Spring MVC官方文档学习笔记(一)之Web入门

    注: 该章节主要为原创内容,为后续的Spring MVC内容做一个先行铺垫 1.Servlet的构建使用 (1) 选择Maven -> webapp来构建一个web应用 (2) 构建好后,打开pom.xml文件,一要注意打包方式为war包,二导入servlet依赖,如下 <!– 打war包 –> <packaging>war…

    Java 2023年5月11日
    00
合作推广
合作推广
分享本页
返回顶部