KMP算法的理解,伪代码,c代码实现

1、字符串问题形式化定义:假设文本是一个长度为n的T[1..n],而模式是一个长度为m的数组P[1..m],其中m<=n,如果有T[s+1..s+m]==P[1..m],那么就称模式P在T中出现。s为有效偏移,否则称为无效偏移。

2、方法:首先基于模式进行预处理,然后找到所有有效偏移(匹配)。

几种方法的预处理时间和匹配时间


算法


预处理时间


匹配时间


朴素算法


0


o((n-m+1)*m)


有限自动机


o(m|所有有限长度字符串的集合|)


o(n)


KMP


o(m)


o(n)


Rabin-karp


0(m)


o((n-m+1)*m)

3、朴素字符串匹配算法:通过循环的方式找到所有有效偏移s。有效偏移s的可能有n-m+1个,每次匹配需要m次,因此共需匹配(n-m+1)*m次。

伪代码:

NAIVE-STRING-MATCHER(T,P)

1. n=T.length

2. m=P.length

3. for s=0 to n-m

4.        if P[1..m] == T[s+1..s+m]

5.                 printf "Pattern occurs with shift" s

缺点:忽略了检测无效s值时获得的文本信息。

4、Rabin-Karp算法:初等数论的概念。暂且不研究。

5、利用有限自动机进行字符串匹配:首先建立好一个有限自动机,然后根据有限自动机进行匹配。

有限自动机:包括五个元素,所有状态的集合,初始状态,接收状态的集合,有限输入字母表,转移函数。

6、KMP算法:通过前缀函数避免对无用偏移进行检测。也可以避免在自动机匹配中,对整个转移函数的计算。主要原因在于字符串中存在部分匹配的现象。

本质:针对待匹配的模式串的特点,判断它是否有重复的字符,从而找到它的前缀与后缀,进而求出相应的Next数组,最终根据Next数组而进行KMP匹配

next数组:记录下字符串P中的共有元素的位置,即第一个共有元素向后便宜多少可以到达第二个相同的元素哪儿。

"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。

大致思路:

kmp的比较函数:

1.首先初始化好NEXT数组, next[0]=0,next[1]=1

2.循环查找模式P是否在T中

1)首先比较P[i] == T[j],如果相等,继续比较下一个,否则执行2.2)

2)令j=next[j],继续比较(这一步避免了回溯)

3)如果j==0; 表明没有匹配,则i++, j++

3.直到找到P在T中的位置或者T已经被比较晚结束。

当发生失配的情况下,j的新值next[j]取决于模式串中T[0 ~ j-1]中前缀和后缀相等部分的长度, 并且next[j]恰好等于这个最大长度

next数组的初始化

1.定义next数组, 令next[0]=0, next[1]=1

2.从p[2]开始循环计算对应的next数组

3.    循环计算next[j]的值

4.        从next[j]往前找到某个p[i]=p[next[i]],如果相等则next[j]=next[i]+1

5.        否则,令i=next[i]继续向前查找,直到找到相等的为止。

6.        如果i=0,则表明模式P中没有p[j]相同的前缀,令next[j]=1

7、伪代码:

初始化NEXT数组

NEXT-FUNC(P, next)

1.let next[1..m] = -1

2.next[1]=0, next[2]=1

3.for i=3 to m

4.     j = i

5.     while j != 0

5.         if P[j] == P[next[j]]

6.               next[i]=next[j]+1

7.               break;

8.         else

9.               j = next[j]

10.    if   j == 0 then next[j] = 1

KMP-CMP(T, P)

1.NEXT-FUNC(P, next), j = 0;

2.for T[i] form T[0] to T[n]

3.    if T[i] == S[j]

4.        if j == m  then retrun true

5.        then i++ j++

6.    else j = next[j];

7.    if j == 0 then i++ j++


#include <stdio.h>int nextArr(char* p, int* next, int m){    next[1] = 0;    next[2] = 1;    int i, j;    for(i=3; i<m; i++){        j=i;        while(j!=0){            if(p[j] == p[next[j]]){                next[i] == next[j]+1;                break;            }else{                j=next[j];            }        }        if(j==0) {            next[j] = 1;        }    }    return 0;}int kmpCMP(char* t, char* p, int n, int m){    int i = 0,j =0;    int next[10];    next[0] = 0;    nextArr(p, next, m);    for(i=0; i<m; i++){        if(t[i]==p[j]){            if(j==m-1){                printf("%d\n", i-m+2);                return 1;            }else{                j++;                continue;            }        }else{            j=next[j];        }        if(j==0){        j=1;        }    }    return 0;}
时间: 2024-08-05 14:00:39

KMP算法的理解,伪代码,c代码实现的相关文章

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

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

KMP算法详细理解

KMP算法详细理解 从昨天开始看KMP算法到今天凌晨..... 把一些知识点进行总结,其实KMP还是挺简单的(HHHHHH) 博客新地址:https://miraitowa2.top/ 1:BF(暴力匹配)算法 假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢? 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有: 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符: 如

KMP算法的理解和代码实现

KMP算法理解参考原文:http://kb.cnblogs.com/page/176818/ 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较.因为B与A不匹配,所以搜索词后移一位. 2. 因为B与A不匹配,搜索词再往后

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

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

字符串匹配KMP算法的理解(详细)

1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱.所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文. 然近期因开了个算法班,班上专门讲解数据结构.面试.算法,才再次仔细回顾了这个KMP,在综合了一些网友的理解.以及算法班的两位讲师朋友曹博.邹博的理解之后,写了9张PPT,发在微博上.随后,一不做二不休,索性将PPT上的内容整理到了本文之中(后来文章越写越完整,所含内容早已不再是九张PPT 那样简单

关于KMP算法的理解

前言 本篇博客的字符串下标是从1开始的. 引入 给出两个字符串\(A,B\),询问\(B\)是否是\(A\)的子串. 对于以上问题,我们有一个比较暴力的想法,就是一位一位去配对呀. 给出代码: int Check(){ for(int i=1;i+M-1<=N;i++){ int j=0; while(j<M&&A[i+j]==B[j+1])j++; if(j==M)return 1; } return 0; } 但是显然,这个算法并不太优秀.(可以被卡到\(O(N\cdot

KMP算法的理解

---恢复内容开始--- 在看数据结构的串的讲解的时候,讲到了KMP算法——一个经典的字符串匹配的算法,具体背景自行百度之,是一个很牛的图灵奖得主和他的学生提出的. 一开始看算法的时候很困惑,但是算法思想很简单,就是在暴力匹配的基础上得出的. 暴力匹配 这里有必要说一下暴力匹配,暴力匹配更简单,就是按照人的常规思维去匹配字符串,拿模式串(P)的第一个字符去和给定串(S)比较,S从左往右看,一看,第一个,呀~不对,啥也不说了,第一个都不对了,后边还比个毛.所以,这一次比较,S中第一个字符开头是匹配

KMP算法 --- 深入理解next数组

KMP算法的前缀next数组最通俗的解释 我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度. 当然我们可以看到这个算法针对的是子串有对称属性,如果有对称属性,那么就需要向前查找是否有可以再次匹配的内容. 在KMP算法中有个数组,叫做前缀数组,也有的叫next数组,每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符,当然它描述的也是子串的对称程度,程度越高,值

KMP算法初步理解

看了两天KMP算法,不知道理解的对不,初步理解总结如下:(主要是各种next数组把自己整晕了,有彻底懂的大神们再给指导下) 首先是思路,"字符串匹配的KMP算法_知识库_博客园"http://kb.cnblogs.com/page/176818/,问题的关键落在求数组上,而求数组实际是对自身求匹配度,所以求next数组的子函数和主函数很类似,所以网上讨论的好像主要是两种next数组,最好把相应的主函数列出来,还有像第二种的next和nextval数组都可用,在主函数相同的情况下,弥补一