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

yizhihongxing

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日

相关文章

  • Go 数据结构之二叉树详情

    Go 数据结构之二叉树详情 二叉树是一种树形数据结构,它的每个节点至多只有两个子节点,通常称为左子节点和右子节点。在本文中,我们将介绍二叉树的定义、遍历方法和常见应用场景。 定义 一个二叉树是一个有根树,它的每个节点最多有两个子节点,用左子树和右子树来区分。 在 Go 代码中,可以通过如下结构体定义表示二叉树的节点: type Node struct { L…

    数据结构 2023年5月17日
    00
  • C语言多维数组数据结构的实现详解

    C语言多维数组数据结构的实现详解 多维数组的定义 多维数组是由若干行和若干列构成的数据类型,它由多个一维数组组成。在C语言中,多维数组的定义和一维数组十分相似,只是在数组定义中增加了方括号以表示维数。 下面是一个二维数组的定义: int arr[3][4]; 上述代码定义了一个3行4列的二维数组,标识符为arr,它包含12个元素。其中arr[0][0]到ar…

    数据结构 2023年5月17日
    00
  • java数据结构和算法中哈希表知识点详解

    Java数据结构和算法中哈希表知识点详解 什么是哈希表 哈希表是一种以键值对(key-value)形式存储数据的数据结构,通过使用哈希函数将对应的键映射为一个索引,使得数据的添加、删除、查找等操作可以在常数时间内完成。 具体来讲,哈希表主要包含以下几个部分: 哈希函数:将键转换为一个索引,通常使用散列算法实现。 数组:用于存储哈希表的元素(键值对)。 冲突解…

    数据结构 2023年5月17日
    00
  • 数据结构与算法中二叉树子结构的详解

    数据结构与算法中二叉树子结构的详解 什么是二叉树子结构 二叉树是一种数据结构,由包含根节点的节点组成,可以拓展为左子树和右子树。二叉树子结构指的是,在一棵二叉树中,具有连续节点的子树。 如何判断是否为二叉树子结构 对于一棵二叉树T和另外一棵二叉树S,我们可以判断S是否为T的子树,遵循以下判断原则: 如果树S为空,则表示S不是T的子树; 如果树S的根节点和树T…

    数据结构 2023年5月17日
    00
  • C语言数据结构与算法之链表(一)

    欢迎阅读本篇文章,本文将为大家详细讲解C语言中数据结构与算法之链表。接下来,将从以下几个方面为大家讲述: 链表的定义 链表的特点 链表的分类 单向链表的实现及应用 双向链表的实现及应用 示例说明 1. 链表的定义 链表是由一系列节点组合而成的数据结构,每个节点都包含了一个数据域和一个指向下一个节点的指针域。其中,链表的头结点为第一个节点,而尾节点为最后一个节…

    数据结构 2023年5月17日
    00
  • Python 数据结构之旋转链表

    Python 数据结构之旋转链表 简介 在进行链表操作时,有时需要旋转链表的一部分,即将链表的最后几个节点移到链表的头部。本文将讲解 Python 实现旋转链表的方法。 方法 我们需要了解两个概念:旋转链表、链表反转。 旋转链表 假设链表为1-2-3-4-5,k=2,将链表后两个节点移动到链表头部,即转化为4-5-1-2-3。 做法如下: 先遍历链表,得出链…

    数据结构 2023年5月17日
    00
  • 一步步带你学习设计MySQL索引数据结构

    一步步带你学习设计MySQL索引数据结构 索引原理 在MySQL中,索引是一种数据结构,用于快速查找表中的记录。在一张表中,可以使用不同的列来创建索引,索引可以大大提高查询效率,减少扫描行数,加快数据查询速度。 索引的实现一般使用的是B树和B+树这两种数据结构,因为它们都具有良好的平衡性,可以快速查找,插入和删除。 如何设计MySQL索引 确认需要优化的查询…

    数据结构 2023年5月17日
    00
  • EMI/EMS/EMC有什么关系?

    EMI(Electromagnetic Interference)直译是“电磁干扰”,是指电子设备(即干扰源)通过电磁波对其他电子设备产生干扰的现象。 从“攻击”方式上看,EMI主要有两种类型:传导干扰和辐射干扰。 电磁传导干扰是指干扰源通过导电介质(例如电线)把自身电网络上的信号耦合到另一个电网络。 电磁辐射干扰往往被我们简称为电磁辐射,它是指干扰源通过空…

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