Java数据结构之AC自动机算法的实现

Java数据结构之AC自动机算法的实现

本文将详细讲解AC自动机算法在Java中的实现方法和原理,同时提供两个示例进行说明,使读者能够深入了解该算法并学会如何使用。

什么是AC自动机算法

AC自动机(Aho-Corasick Automaton)是多模式匹配的一种经典算法,其基本思路是将多个模式串构建成一颗“字典树”,然后对输入的文本串进行扫描匹配。相比于简单的暴力匹配方法,AC自动机算法可以在时间复杂度为O(n)的情况下实现多模式匹配,在诸如关键词过滤、字符串匹配等场景中具有很高的应用价值。

AC自动机算法的实现主要分为以下三个步骤:

  1. 构建trie树:将所有模式串构建成一个trie树;
  2. 对trie树进行预处理:为每个节点计算出其在trie树上的fail指针,并将所有模式串的状态存储到一个状态集合中;
  3. 使用AC自动机模式匹配算法:对输入的文本串进行扫描匹配,每遇到一个字符就在trie树上进行前缀匹配,并跟随其相应的fail指针回溯到其下一个状态,直到匹配成功或达到文本串的末尾。

Java实现

构建trie树

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

    public TrieNode() {
        this.children = new HashMap<>();
        this.isEndOfWord = false;
        this.patterns = new HashSet<>();
    }
}

class Trie {
    private TrieNode root;

    /**
     * Initialize your data structure here.
     */
    public Trie() {
        root = new TrieNode();
    }

    /**
     * Inserts a word into the trie.
     */
    public void insert(String word) {
        TrieNode curr = root;
        for (char c : word.toCharArray()) {
            curr.children.putIfAbsent(c, new TrieNode());
            curr = curr.children.get(c);
        }
        curr.isEndOfWord = true;
        curr.patterns.add(word); // 记录该节点所包含的所有模式串
    }
}

计算fail指针

class ACNode {
    char c; // 该节点代表的字符
    ACNode fail; // fail指针
    Map<Character, ACNode> children; // 子节点
    Set<String> patterns; // 存储该节点包含的所有模式串

    // 计算该节点的fail指针
    public void computeFailPointer() {
        Queue<ACNode> queue = new LinkedList<>();
        for (Map.Entry<Character, ACNode> entry : children.entrySet()) {
            char c = entry.getKey();
            ACNode child = entry.getValue();
            child.fail = this;
            queue.offer(child);
        }
        while (!queue.isEmpty()) {
            ACNode curr = queue.poll();
            for (Map.Entry<Character, ACNode> entry : curr.children.entrySet()) {
                char c = entry.getKey();
                ACNode child = entry.getValue();
                ACNode fail = curr.fail;
                while (fail != null && !fail.children.containsKey(c)) {
                    fail = fail.fail;
                }
                child.fail = fail == null ? this : fail.children.get(c);
                child.patterns.addAll(child.fail.patterns);
                queue.offer(child);
            }
        }
    }
}

class AC {
    private ACNode root;

    public AC(Trie trie) {
        root = new ACNode();
        for (Map.Entry<Character, TrieNode> entry : trie.root.children.entrySet()) {
            char c = entry.getKey();
            TrieNode child = entry.getValue();
            ACNode acChild = new ACNode();
            acChild.c = c;
            root.children.put(c, acChild);
            acChild.patterns.addAll(child.patterns);
            acChild.fail = root;
        }
        root.fail = root;
    }

    // 计算AC自动机的所有fail指针
    public void computeFailPointers() {
        root.computeFailPointer();
    }
}

AC自动机模式匹配

class ACAutomaton {
    private AC ac;

    public ACAutomaton(Trie trie) {
        ac = new AC(trie);
        ac.computeFailPointers();
    }

    public List<String> findAllOccurrences(String text) {
        List<String> res = new ArrayList<>();
        ACNode curr = ac.root;
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            while (curr != null && !curr.children.containsKey(c)) {
                curr = curr.fail;
            }
            if (curr == null) {
                curr = ac.root;
            } else {
                curr = curr.children.get(c);
                curr.patterns.forEach(res::add);
            }
        }
        return res;
    }
}

示例说明

示例一

假设有字符串集合{“she”, “he”, “say”, “sh”, “shr”, “her”},并且要在下面这段文本中找出所有的模式串:

she says he has her shrubs

对该文本进行扫描匹配,最终找出的模式串是:

she, he, her, shr, say

示例二

假设有字符串集合{“cc”, “ccc”, “cccc”},并且要在下面这段文本中找出所有的模式串:

abccccde

对该文本进行扫描匹配,最终找出的模式串是:

cc, ccc, cccc

总结

以上是AC自动机算法在Java中的实现方法和原理,本文详细讲解了AC自动机的实现过程和三个步骤,并同时提供了两个示例,希望能够帮助读者深入了解该算法并学会使用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java数据结构之AC自动机算法的实现 - Python技术站

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

相关文章

  • C++数据结构之哈希算法详解

    C++数据结构之哈希算法详解 概述 哈希算法是一种常用于对数据进行快速检索的算法,它通常将数据映射为一个较短的指纹码,并将这个指纹码作为数据的索引值,这样可以快速地根据索引值找到对应的数据。 本文将详细讲解哈希算法的实现原理、常见应用场景以及在 C++ 语言中如何实现一个简单的哈希表。 哈希算法的实现原理 哈希算法的核心思想是将输入数据通过一个哈希函数进行映…

    数据结构 2023年5月17日
    00
  • C语言全面梳理结构体知识点

    C语言全面梳理结构体知识点 什么是结构体? 结构体是一种自定义的数据类型,它可以包含多个不同类型的成员变量,并且这些成员变量可以通过一个变量名来访问。结构体的定义需要使用关键字struct,并且需要指定结构体的类型名和成员变量。例如: struct Person { char name[20]; int age; float height; }; 以上代码就…

    数据结构 2023年5月17日
    00
  • redis数据结构之intset的实例详解

    Redis数据结构之intset的实例详解 介绍 Redis是一个高性能的key-value存储系统,支持多种数据结构。其中,intset是Redis内置的一种特殊的数据结构,它可以高效地存储整型数据。 本篇文章将介绍intset的基本特性、底层实现以及相关用例,以便读者能够更好地了解该数据结构在Redis中的应用。 intset的基本特性 intset是一…

    数据结构 2023年5月17日
    00
  • 「双端队列BFS」电路维修

    本题为3月23日23上半学期集训每日一题中B题的题解 题面 题目描述 Ha’nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上。Rika的家里有一辆飞行车。有一天飞行车的电路板突然出现了故障,导致无法启动。 电路板的整体结构是一个R行C列的网格( \(R,C \leq 500\) ),如右图所示。每个格点都是…

    算法与数据结构 2023年4月18日
    00
  • js处理层级数据结构的方法小结

    “JS处理层级数据结构的方法小结”是一篇讲解JavaScript如何处理嵌套数据结构的文章。在现代的web应用中,嵌套结构是非常常见的,比如JSON数据、树形数据等。以下是对该话题的详细讲解: 1. 嵌套数据结构的概念 指的是包含嵌套关系的数据类型,如数组、对象、树形结构、XML文档等。这些类型之间有着固定层级关系,包含多个层次的数据。嵌套数据结构的处理,往…

    数据结构 2023年5月17日
    00
  • C语言数据结构实现银行模拟

    C语言数据结构实现银行模拟攻略 背景介绍 银行模拟是计算机学科中一个重要的数据结构实践练习项目。它涉及到队列(Queue)等数据结构的应用,也是计算机基础课程的一个重要组成部分。 代码实现 1. 队列的实现 首先,我们需要实现一个队列(Queue)结构体,包含 QueueSize、Front、Rear 三个成员变量: struct Queue { int Q…

    数据结构 2023年5月17日
    00
  • C语言学习之链表的实现详解

    下面我将详细讲解“C语言学习之链表的实现详解”的完整攻略。 1. 链表的定义 链表是一种数据结构,它由一系列节点组成。每个节点由一个数据部分和一个指向下一个节点的地址部分组成。链表可以有多种形式,例如单向链表、双向链表、循环链表等。 2. 链表的实现 2.1. 单向链表 单向链表是最简单的链表形式,一个节点只包含一个指向下一个节点的指针。在C语言中,我们可以…

    数据结构 2023年5月17日
    00
  • Java链表数据结构及其简单使用方法解析

    Java链表数据结构及其简单使用方法解析 概述 链表是一种非线性结构,由一系列节点按照顺序连接而成。每个节点由数据域和指针域组成,数据域用于存储数据,指针域用于指向下一个节点或者上一个节点。在Java中,链表有多种实现方式,常见的有单向链表、双向链表等。 单向链表的实现 以下是一个单向链表的实现代码示例: public class Node { privat…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部