Java数据结构之KMP算法的实现

Java数据结构之KMP算法的实现

1. KMP算法的概述

KMP算法的全称是Knuth-Morris-Pratt算法,是一种字符串匹配算法,用于在文本串S内查找一个模式串P的出现位置。它的特点是在P和S两个序列中,当匹配失败时,它会跳过P的部分已匹配的字符,利用这个信息来减少S和P之间的匹配次数,从而提高匹配效率。

2. KMP算法的实现

2.1 预处理失配函数

KMP算法中的一个重要概念是前缀和后缀。对于一个字符串P,它的前缀是指从第一个字符开始,一直到某一位置的子串。例如,对于字符串“abcd”,它的前缀包括“a”、“ab”、“abc”和“abcd”。后缀则是从某一位置往后,一直到最后一个字符的子串。例如,对于字符串“abcd”,它的后缀包括“d”、“cd”、“bcd”和“abcd”。

失配函数(也称为部分匹配表)是KMP算法中的核心,它记录了模式串每一位在匹配失败时,应该跳过的最长前缀和后缀。具体的,假设我们已经得到了字符串P的失配函数mp,它可以通过以下方法计算得到:

private static int[] buildNext(String p) {
    int[] next = new int[p.length()];
    next[0] = -1;
    int i = 0, j = -1;
    while (i < p.length() - 1) {
        if (j == -1 || p.charAt(i) == p.charAt(j)) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
    return next;
}

下面是计算“ababc”的失配函数的过程:

 a b a b c
 -1 0 0 1 2

对于位置i,失配函数mp[i],表示p[0]~p[mp[i] - 1]和p[i - mp[i] + 1]~p[i]这两个段的字符是相同的。

2.2 匹配过程

在计算出失配函数之后,我们就可以在字符串S中查找模式串P了。具体的流程如下:

  1. 定义两个指针i和j,分别指向S和P中的当前字符
  2. 如果S[i] == P[j],则i和j都往后移动继续匹配
  3. 如果S[i] != P[j],则根据失配函数mp[j]更新j的位置,并继续和S[i]匹配
  4. 如果j已经到达P的末尾,则表示匹配成功,返回i - j的值,即匹配到的位置,否则返回-1,表示匹配失败

下面是对字符串“abcabcababc”的匹配过程:

    S: a b c a b c a b a b c
        |           |
    P: a b c a b c a b a b c
        |           |
mp[j]:-1 0 0 1 2 3 4 2 0 1 2

可以看到,在S的第8个字符出现匹配失败时,我们根据失配函数mp[j]更新j的位置到4(即P的第5个字符),然后继续和S[i]匹配,直到匹配成功。

3. 示例说明

下面是两个例子,演示了如何使用Java实现KMP算法:

3.1 示例1

假设我们需要在字符串“ababcabcababdef”中查找模式串“abcab”的位置。可以使用以下代码:

public static void main(String[] args) {
    String s = "ababcabcababdef";
    String p = "abcab";
    int pos = kmp(s, p);
    System.out.println(pos);
}

private static int kmp(String s, String p) {
    int[] next = buildNext(p);
    int i = 0, j = 0;
    while (i < s.length() && j < p.length()) {
        if (j == -1 || s.charAt(i) == p.charAt(j)) {
            i++;
            j++;
        } else {
            j = next[j];
        }
    }
    if (j == p.length()) {
        return i - j;
    } else {
        return -1;
    }
}

3.2 示例2

假设我们需要在文本文件中查找所有包含字符串“abcab”的行,可以使用以下代码:

public static void main(String[] args) throws IOException {
    String p = "abcab";
    BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
    String line;
    while ((line = reader.readLine()) != null) {
        int pos = kmp(line, p);
        if (pos != -1) {
            System.out.println(line);
        }
    }
    reader.close();
}

private static int kmp(String s, String p) {
    int[] next = buildNext(p);
    int i = 0, j = 0;
    while (i < s.length() && j < p.length()) {
        if (j == -1 || s.charAt(i) == p.charAt(j)) {
            i++;
            j++;
        } else {
            j = next[j];
        }
    }
    if (j == p.length()) {
        return i - j;
    } else {
        return -1;
    }
}

这个例子中,我们使用了Java的输入输出流来读取文件中的每一行,并对每一行进行KMP匹配操作,查找所有包含模式串的行。注意,这个代码只是提供了一种示例,实际上在处理大型文本文件时,我们需要使用更高效的技术来进行匹配,例如AC自动机等。

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

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

相关文章

  • Java面试题冲刺第十九天–数据库(4)

    本篇攻略是针对Java数据库相关面试题的,为了方便浏览,我将其分为以下几个部分: 1. 数据库连接池 在Java开发中,我们使用JDBC连接数据库进行数据操作时,为了提高数据库访问性能,通常会使用数据库连接池技术。常见的数据库连接池有:C3P0、Druid、HikariCP等。 C3P0 C3P0是一个开源的数据库连接池,可以设置最大连接数、最小连接数、最大…

    数据结构 2023年5月17日
    00
  • C语言数据结构之串插入操作

    C语言数据结构之串插入操作 在C语言中,字符串是一种常见的数据类型,可以用字符数组来表示。当需要在字符串中插入新的字符时,就需要用到串插入操作。本文将详细讲解如何实现串插入操作。 串插入操作的实现 串插入操作的基本思路是:首先需要在插入位置后的字符串中腾出足够的空间,再把插入的内容拷贝到这个空间中。具体实现分以下步骤: 步骤1:计算需要插入位置的字符下标 需…

    数据结构 2023年5月17日
    00
  • 蒙特卡罗方法:当丢失确定性时的处理办法

    一、简介   蒙特卡罗(Monte Carlo),也可翻译为蒙特卡洛,只是不同的音译选词,比较常用的是蒙特卡罗。是摩洛哥的一片城区,以拥有豪华赌场闻名,蒙特卡罗方法是基于概率的。基本思想:如果你想预测一件事情的结果,你只要把随机生成的各种输入值,把这件事模拟很多遍,根据模拟出的结果就可以看到事情的结果大致是什么情况。蒙特卡罗算法是基于蒙特卡罗方法的算法。 二…

    算法与数据结构 2023年4月17日
    00
  • Java 数据结构算法Collection接口迭代器示例详解

    Java 数据结构算法 Collection 接口迭代器示例详解 如果你正在学习 Java 编程,那么数据结构和算法一定是一个不可避免的话题。在 Java 中,Collection 框架提供了许多有用的接口和类来管理和操作集合。其中,迭代器 Iterator 是 Collection 中最重要的接口之一,它提供了对集合元素进行迭代的方法。本文将对 Java …

    数据结构 2023年5月17日
    00
  • Java数据结构之LinkedList的用法详解

    Java数据结构之LinkedList的用法详解 LinkedList简介 LinkedList是Java中的一个数据结构,它是一个双向链表,可以提供快速的插入和删除操作。LinkedList中的元素分别保存在每个节点中,每个节点包含了指向前一个节点和后一个节点的引用。 使用LinkedList的好处是,其可以快速的进行插入和删除操作,但是如果需要随机存取中…

    数据结构 2023年5月17日
    00
  • C语言数据结构之堆排序的优化算法

    C语言数据结构之堆排序的优化算法攻略 堆排序简介 堆排序(HeapSort)是一种树形选择排序,在排序过程中始终保持一个最大堆,每次将堆顶元素与最后一个元素交换位置,并进行一次最大堆调整操作,直到整个序列有序为止。 堆排序的时间复杂度为O(nlogn),具有不需额外存储空间的特点,因此广泛应用于内存受限的场景。 堆排序的优化算法 1. 建堆操作的优化 将序列…

    数据结构 2023年5月17日
    00
  • Java数据结构之线索化二叉树的实现

    Java数据结构之线索化二叉树的实现 线索化二叉树的概述 线索化二叉树(Threaded Binary Tree)是一种优化的二叉树结构。它的优点是可以在O(n)的时间复杂度内,进行中序遍历。而在普通二叉树中进行中序遍历需要的时间复杂度是O(nlogn)。线索化二叉树的原理是利用空闲的指针域,来记录中序遍历中前驱与后继结点的位置。线索化二叉树中会出现两种类型…

    数据结构 2023年5月17日
    00
  • 【ACM组合数学 | 错排公式】写信

    题目链接:https://ac.nowcoder.com/acm/contest/54484/B 题意很简单,但是数据范围偏大。 错排公式 首先来推导一下错排公式: \[D(n) = n!\sum_{k=0}^{n}\frac{(-1)^k}{k!} \] 设一个函数: \[S_i表示一个排列中p_i = i的方案数 \] 那么我们可以知道: \[D(n) …

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