用C++与Java代码实现KMP算法实例

KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。比较流行的做法是实现一个next()函数,函数本身包含了模式串的局部匹配信息。由于next函数理解起来不太容易,本文同样是基于空间换时间的做法,但将采用另一种代码实现,希望可以更方便读者理解!

测试数据

aseeesatba   esat
as330kdwejjl_8   jjl_
faw4etoesting tio
aabacb abac

测试结果

4
9
-1
0

(注:若匹配则返回text子串的起始index;否则返回-1)

1.暴力查找的实现一

// 暴力子串查找一式:O(M*N)
    private static int search0(String text, String pat) {
        int i, j, N = text.length(), M = pat.length();
        for (i = 0; i <= N - M; i++) {
            for (j = 0; j < M; j++) {
                if (text.charAt(i + j) != pat.charAt(j))
                    break;
            }
            if (M == j)
                return i;
        }
        return -1;
    }

函数传入文本text和模式串pat,其中i和i+j分别标记text子串的首尾。若text存在子串匹配pat,则返回text子串起始index;否则返回-1;时间复杂度:O(M*N)

2.暴力查找实现二

// 暴力子串查找二式:O(M*N)
    public static int search(String text, String pat) {
        int i, j;
        int N = text.length(), M = pat.length();
        for (i = 0, j = 0; i < N && j < M; i++) {
            if (text.charAt(i) == pat.charAt(j))
                j++;
            else {
                i -= j;
                j = 0;
            }
        }
        return (j == M) ? (i - M) : -1;
    }

同样的一种暴力查找算法,通过不断的回溯文本串中的“i”进行判断。若text存在子串匹配pat,则返回text子串起始index;否则返回-1;时间复杂度:O(M*N)

3.KMP算法(空间换时间)

为了优化算法时间复杂度,我们尝试进行一些信息存储,引入了额外的空间存储 dfa[][]。

从上述第二种暴力查找算法中,我们可以得到启发。即,通过记录“j”保证“i”只能往右移动,无需往左回退。其中,dfa[i][j]

表示文本串中当前字符‘charAt(i)’时,下个文本字符'charAt(i+1)'应该与模式串匹配的位置(0~j)。

这里我们引入有穷自动机DFA对dfa[][]进行数值的初始化。以模式串“aabacb”为例,匹配pat的DFA状态图如下:

对应的代码如下:

//构造dfa[][]
        dfa[pat.charAt(0)][0] = 1;
        for(int X=0,j=0;j<M;j++){
            for(int c=0;c<R;c++){
                dfa[c][j] = dfa[c][X];
            }
            dfa[pat.charAt(j)][j] = j+1;
            X = dfa[pat.charAt(j)][X];
        }

其中,“X”表示不同的dfa状态,上述代码构造dfa[][]的时间复杂度为:O(N*R);

------------------------------------------------

Java完整代码

package ch05.string.substring;

import java.io.File;
import java.util.Scanner;

public class KMP {
    
    private int R = 255;
    private String pat;
    private int[][] dfa;
    
    public KMP(String pat) {
        this.pat = pat;
        int M = pat.length();
        dfa = new int[R][M];
        
        //构造dfa[][]
        dfa[pat.charAt(0)][0] = 1;
        for(int X=0,j=0;j<M;j++){
            for(int c=0;c<R;c++){
                dfa[c][j] = dfa[c][X];
            }
            dfa[pat.charAt(j)][j] = j+1;
            X = dfa[pat.charAt(j)][X];
        }
        
    }
    
    public int search(String text){
        int i,j;
        int N = text.length(),M = pat.length();
        for(i=0,j=0;i<N && j<M; i++){
            j = dfa[text.charAt(i)][j];
        }
        return j==M?(i-M):-1;
    }
    
    public static void main(String[] args) throws Exception {
        //从文件读入数据
        Scanner input = new Scanner(new File("datain.txt"));
        while(input.hasNext()){
            String text = input.next();
            KMP kmp = new KMP(input.next());
            int ans = kmp.search(text);
            //输出答案
            System.out.println(ans);
        }
    }
}

------------------------------------------------

C/C++完整代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int maxn=1e4+10;
const int R=256;
int dfa[R][maxn];

string text,pat;
void init(){
    int M=pat.length();
    dfa[pat[0]][0] = 1;
    for(int X=0,j=1;j<M;j++){
        /**直接从dfa[][X]复制到dfa[][j]*/
        for(int c=0;c<R;c++){
            dfa[c][j] = dfa[c][X];
        }
        /**匹配到,继续往右走*/
        dfa[pat[j]][j] = j+1;
        X = dfa[pat[j]][X];
    }

}
int search1(){
    init();
    int i,j,N = text.length(),M = pat.length();
    for(i=0,j=0;i<N && j<M;i++){
        j = dfa[text[i]][j];
    }
    return j==M?(i-M):-1;
}
int main(){
    freopen("datain.txt","r",stdin);
    while(cin>>text>>pat){
        cout<<search1()<<endl;
    }
    return 0;
}

时间: 2024-10-29 08:25:55

用C++与Java代码实现KMP算法实例的相关文章

java代码获取JVM基本信息实例

问题描述 java代码获取JVM基本信息实例 包括虚占用CPU时间,JIT编译器名称,JIT编译总时间,JVM启动参数 解决方案 http://cn-done.iteye.com/blog/2041971 解决方案二: http://cn-done.iteye.com/blog/2041971

Java实现二分查找算法实例分析_java

本文实例讲述了Java实现二分查找算法.分享给大家供大家参考.具体如下: 1. 前提:二分查找的前提是需要查找的数组必须是已排序的,我们这里的实现默认为升序 2. 原理:将数组分为三部分,依次是中值(所谓的中值就是数组中间位置的那个值)前,中值,中值后:将要查找的值和数组的中值进行比较,若小于中值则在中值前面找,若大于中值则在中值后面找,等于中值时直接返回.然后依次是一个递归过程,将前半部分或者后半部分继续分解为三部分.可能描述得不是很清楚,若是不理解可以去网上找.从描述上就可以看出这个算法适合

python实现的二叉树算法和kmp算法实例_python

主要是:前序遍历.中序遍历.后序遍历.层级遍历.非递归前序遍历.非递归中序遍历.非递归后序遍历 复制代码 代码如下: #!/usr/bin/env python#-*- coding:utf8 -*- class TreeNode(object):    def __init__(self, data=None, left=None, right=None):        self.data = data        self.left = left        self.right =

C语言中实现KMP算法的实例讲解_C 语言

一般的算法为什么这么低效呢?那是因为主串指针回溯情况过多: 主串指针如果不回溯的话,速度就会加快,那我们就会想: 如何让主串指针不回溯? KMP算法就是解决了这个问题,所以速度变得更快速了. 它是这样子的: 用一个数组:next[] 求得失配时的位置,然后保存下来. 要说清楚KMP算法,可以从朴素的模式匹配算法说起.  朴素的模式匹配算法比较容易理解,其实现如下    int Index(char s[], char p[], int pos) { int i, j, slen, plen; i

JAVA实现KMP算法理论和示例代码_java

一.理论准备KMP算法为什么比传统的字符串匹配算法快?KMP算法是通过分析模式串,预先计算每个位置发生不匹配的时候,可以省去重新匹配的的字符个数.整理出来发到一个next数组, 然后进行比较,这样可以避免字串的回溯,模式串中部分结果还可以复用,减少了循环次数,提高匹配效率.通俗的说就是KMP算法主要利用模式串某些字符与模式串开头位置的字符一样避免这些位置的重复比较的.例如 主串: abcabcabcabed ,模式串:abcabed.当比较到模式串'e'字符时不同的时候完全没有必要从模式串开始位

C++ kmp算法模板代码解读

C++编程语言虽然功能强大,应用方式灵活,但是在实际编程中同样会出现各种各样的错误.在这里我们将会为大家详细介绍一下有关C++指针漂移的解决方法,希望本文介绍的内容可以帮助大家解决问题. 最近我们在工作中碰到一个奇怪的问题,最后确定是多继承引起的C++指针漂移,跟C++对象模型有关.示意如下: class A {...}; class B{...}; class AB : public B, public A {...} ... AB *pab = new AB(); A* pa = (A*)p

链表-求助Java算法,这两个算法问题有Java代码实现

问题描述 求助Java算法,这两个算法问题有Java代码实现 从N个元素集合里面随机抽取M个元素(M<N). C/C++: void randomChoose(int*data, intn, int *result, int m); Java: void randomChoose(int data[], int result[]); 说明: 1.Data是待抽取的元素集合,n是data的长度,result是抽取的结果,m是结果集的长度. 2.同一个元素不能被反复抽取. 3.每个元素被抽取到的概率

多种负载均衡算法及其Java代码实现

首先给大家介绍下什么是负载均衡(来自百科) 负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展 网络设备和 服务器的带宽.增加 吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web 服务器. FTP服务器. 企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务. 本文讲述的是"将外部发送来的请求均匀分配到对称结构中的某一台服务器上"的各种算法,并以Java代

算法难题设计出java代码或者伪代码,大牛请进。

问题描述 算法难题设计出java代码或者伪代码,大牛请进. 把 1 2 3 4 5 6 7 8 9 放入三个数组里面 数组可以是空的.. 数组里面的数 是有序的 比如 {1 2 3} { 4 5 6 } { 7 8 9 }:{356789},{124},{}能穷举吗.打印出来 解决方案 {123456789},{},{} 可以么,如果是可以的话,那么是非常简单的 解决方案二: 我是一个刚刚学习编程半年的小白,有点思路,可能不准确,抛砖引玉.我觉得这个题的实质,是对1 2 3 4 5 6 7 8