经典KMP算法C++与Java实现代码

前言:

  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.暴力查找的实现一

 1 // 暴力子串查找一式:O(M*N)
 2     private static int search0(String text, String pat) {
 3         int i, j, N = text.length(), M = pat.length();
 4         for (i = 0; i <= N - M; i++) {
 5             for (j = 0; j < M; j++) {
 6                 if (text.charAt(i + j) != pat.charAt(j))
 7                     break;
 8             }
 9             if (M == j)
10                 return i;
11         }
12         return -1;
13     }

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

2.暴力查找实现二

 1 // 暴力子串查找二式:O(M*N)
 2     public static int search(String text, String pat) {
 3         int i, j;
 4         int N = text.length(), M = pat.length();
 5         for (i = 0, j = 0; i < N && j < M; i++) {
 6             if (text.charAt(i) == pat.charAt(j))
 7                 j++;
 8             else {
 9                 i -= j;
10                 j = 0;
11             }
12         }
13         return (j == M) ? (i - M) : -1;
14     }

    同样的一种暴力查找算法,通过不断的回溯文本串中的“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状态图如下:

    对应的代码如下:

1         //构造dfa[][]
2         dfa[pat.charAt(0)][0] = 1;
3         for(int X=0,j=0;j<M;j++){
4             for(int c=0;c<R;c++){
5                 dfa[c][j] = dfa[c][X];
6             }
7             dfa[pat.charAt(j)][j] = j+1;
8             X = dfa[pat.charAt(j)][X];
9         }

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

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

Java完整代码

 1 package ch05.string.substring;
 2
 3 import java.io.File;
 4 import java.util.Scanner;
 5
 6 public class KMP {
 7
 8     private int R = 255;
 9     private String pat;
10     private int[][] dfa;
11
12     public KMP(String pat) {
13         this.pat = pat;
14         int M = pat.length();
15         dfa = new int[R][M];
16
17         //构造dfa[][]
18         dfa[pat.charAt(0)][0] = 1;
19         for(int X=0,j=0;j<M;j++){
20             for(int c=0;c<R;c++){
21                 dfa[c][j] = dfa[c][X];
22             }
23             dfa[pat.charAt(j)][j] = j+1;
24             X = dfa[pat.charAt(j)][X];
25         }
26
27     }
28
29     public int search(String text){
30         int i,j;
31         int N = text.length(),M = pat.length();
32         for(i=0,j=0;i<N && j<M; i++){
33             j = dfa[text.charAt(i)][j];
34         }
35         return j==M?(i-M):-1;
36     }
37
38     public static void main(String[] args) throws Exception {
39         //从文件读入数据
40         Scanner input = new Scanner(new File("datain.txt"));
41         while(input.hasNext()){
42             String text = input.next();
43             KMP kmp = new KMP(input.next());
44             int ans = kmp.search(text);
45             //输出答案
46             System.out.println(ans);
47         }
48     }
49 }

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

C/C++完整代码  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<string>
 5 using namespace std;
 6 const int maxn=1e4+10;
 7 const int R=256;
 8 int dfa[R][maxn];
 9
10 string text,pat;
11 void init(){
12     int M=pat.length();
13     dfa[pat[0]][0] = 1;
14     for(int X=0,j=1;j<M;j++){
15         /**直接从dfa[][X]复制到dfa[][j]*/
16         for(int c=0;c<R;c++){
17             dfa[c][j] = dfa[c][X];
18         }
19         /**匹配到,继续往右走*/
20         dfa[pat[j]][j] = j+1;
21         X = dfa[pat[j]][X];
22     }
23
24 }
25 int search1(){
26     init();
27     int i,j,N = text.length(),M = pat.length();
28     for(i=0,j=0;i<N && j<M;i++){
29         j = dfa[text[i]][j];
30     }
31     return j==M?(i-M):-1;
32 }
33 int main(){
34     freopen("datain.txt","r",stdin);
35     while(cin>>text>>pat){
36         cout<<search1()<<endl;
37     }
38     return 0;
39 }

Reference:

  【1】Algorithms(4th) -谢路云

【2】http://baike.baidu.com/link?url=_WLufLz1lw2e4eMgU6DI8IblUkp838Qf595Nqxfg2JN3aqNED2FFe3U6J9yPmUv_zKfFqAAQJid7Gzho3ork8K

时间: 2024-10-10 10:29:23

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

数据结构与算法JavaScript (五) 串(经典KMP算法)

数据结构与算法JavaScript (五) 串(经典KMP算法) KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配是指:模式串和母串的的比较从右到左,模式串的移动从左到右. 通过上一章显而易见BF算法也是属于前缀的算法,不过就非常霸蛮的逐个匹配的效率自然不用提了O(mn),网上蛋疼的KMP是讲解很多,基本都是走的高大上路线看的你也是一头雾水,我试

KMP算法详解(图示+代码)

算法过程非常绕,不要企图一次就能看明白,多尝试就会明白一些.下面试图用比较直观的方法解释这个算法,对KMP算法的解释如下: 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较.因为B与A不匹配,所以搜索词后移一位. 2. 因为B与A不匹配,搜索词再往后移. 3. 就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止. 4. 接着比较字符串和搜索词的下一个字符,还是相同. 5. 直到字

poj 3461 - Oulipo 经典kmp算法问题

2017-08-13 19:31:47 writer:pprp 对kmp算法有了大概的了解以后,虽然还不够深入,但是已经可以写出来代码,(可以说是背会了) 所以这道题就作为一个模板,为大家使用吧. 题目大意:给你一个子串P和一个主串S,求在主串中有多少个子串? 代码如下:(需要注意的点我都标记好了,两个函数可以直接用) #include <iostream> #include <cstdio> #include <cstdlib> #include <cstrin

常用排序算法简介以及Java实现代码

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列.分内部排序和外部排序.若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序.反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序. 稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的. 冒泡,插入,基数,归并属于稳定排序 选择,快速,希尔,堆

几个比较经典的算法问题的java实现

1.八皇后问题 1 public class EightQueen { 2 3 private static final int ROW = 16; 4 private static final int COL = 16; 5 6 private static int count = 0; // 八皇后的解的个数 7 8 private static boolean[][] maps = new boolean[ROW][COL]; // 初始化二维数组,模拟8*8棋盘,默认值是false表示没

一文搞定十大经典排序算法(Java实现)

本文总结十大经典排序算法及变形,并提供Java实现. 参考文章: 十大经典排序算法总结(Java语言实现) 快速排序算法—左右指针法,挖坑法,前后指针法,递归和非递归 快速排序及优化(三路划分等) 一.排序算法概述 1.定义 将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序. 2.分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过比较

KMP算法浅析

背景: KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字.其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n). KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配:若next[j]=-1,则将i右移1位,并将j置0,继续进行比较.

8592 KMP算法

时间限制:1000MS  内存限制:1000K 题型: 编程题   语言: 无限制 描述 用KMP算法对主串和模式串进行模式匹配.本题目给出部分代码,请补全内容. #include "stdio.h" #include "stdlib.h" #include "iostream.h" #define TRUE  1 #define FALSE  0 #define OK  1 #define ERROR  0 #define INFEASLBLE

KMP算法具体解释(转)

作者:July. 出处:http://blog.csdn.net/v_JULY_v/. 引记 此前一天,一位MS的朋友邀我一起去与他讨论高速排序,红黑树,字典树,B树.后缀树,包含KMP算法,只有在解说KMP算法的时候,言语磕磕碰碰,我想,原因有二:1.博客内的东西不常回想,忘了不少:2.便是我对KMP算法的理解还不够彻底,自不用说解说自如,运用自如了.所以,特再写本篇文章.因为此前,个人已经写过关于KMP算法的两篇文章,所以,本文名为:KMP算法之总结篇. 本文分为例如以下六个部分: 第一部分