KMP算法文献综述

合集下载

数据结构——KMP算法

数据结构——KMP算法

数据结构——KMP算法算法介绍 KMP算法是⼀种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此⼈们称它为克努特—莫⾥斯—普拉特操作(简称KMP算法)。

KMP算法的核⼼是利⽤匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的⽬的。

具体实现就是通过⼀个next()函数实现,函数本⾝包含了模式串的局部匹配信息。

KMP算法的时间复杂度O(m+n)。

next数组 我们记主串为字符串S,模式串为字符串P。

我们⽤next[j]表⽰以字符Pj结尾的⼦串的长度相等的前缀字符串与后缀字符串长度的最⼤值。

特别地,当没有满⾜条件的⼦串时,next[j] = 0。

为了⽅便起见,我们将字符串从下标1开始匹配。

如此,next数组所表⽰的长度就与下标数值相等了。

算法思路 我们从左到右依次枚举S的每⼀个字符Si,对于当前待匹配字符Si,我们假设当前P字符串中已匹配到Pj。

那么我们只需判断Si和Pj+1,若两者相同,则继续匹配。

若两者不相同,那么我们使j=next[j],即可最⼤限度的减少匹配次数。

因为S字符串的从某位置开始到前i-1的部分与P字符串的前j个字符已匹配(即完全相同),如图中两蓝⾊直线所夹的S、P的两段,⽽P1到Pnext[j]部分是长度最⼤的与以Pj结尾的后缀完全相同的前缀(图中绿⾊线段),⽽该以Pj结尾的后缀则必定与S中⼀段以Si-1结尾的⼦串完全相同,因⽽保证了上述操作的正确性。

接下去只需重复上述操作即可。

⽽对于next数组的预处理,也同上述操作类似,我们只需要以字符串P来匹配字符串P即可。

模板呈现 模板题链接: 代码如下:#include <iostream>#include <algorithm>#include <cstdio>using namespace std;const int M = 1e5+10;int n,m;int ne[M];char s[M],p[M];int main(){cin>>n>>p+1;cin>>m>>s+1;for(int i=2,j=0;i<=n;i++){while(j && p[i]!=p[j+1])j=ne[j];if(p[i]==p[j+1])j++;ne[i]=j;}for(int i=1,j=0;i<=m;i++){while(j && s[i]!=p[j+1])j=ne[j];if(s[i]==p[j+1])j++;if(j==n){printf("%d ",i-n+1-1);j=ne[j]; //可有可⽆,好习惯要加上。

KMP算法详解范文

KMP算法详解范文

KMP算法详解范文KMP算法(Knuth-Morris-Pratt算法)是一种经典的字符串匹配算法,用于在文本中查找一个模式串(pattern)的出现位置。

相对于朴素的字符串匹配算法,KMP算法具有更高的效率,特别是在处理大量数据时。

KMP算法的核心思想是利用已经匹配过的信息来避免不必要的回溯。

朴素的字符串匹配算法是一种从文本的每一位字符开始与模式串进行比较的方法,当匹配失败时,会进行回溯,然后再继续从下一位字符开始匹配。

这样的回溯操作会导致算法的效率降低。

KMP算法通过构造一个部分匹配表(partial match table)来实现。

部分匹配表是一个数组,用于记录模式串中每个位置的最长匹配前缀的长度。

具体来说,部分匹配表中的每个元素记录的是对应位置前缀的最长相等前后缀的长度。

例如,假设模式串为"ABCDABD",部分匹配表的内容如下:位置0123456模式串ABCDABD部分匹配值0000120部分匹配表的构造过程是通过逐个字符的比较来完成的。

具体的步骤如下:1.第一个位置的部分匹配值设为0;2.从第二个位置开始,如果模式串中当前位置的字符与前面位置的字符相等,则部分匹配值为前一个位置的部分匹配值加1;3.如果模式串中当前位置的字符与前面位置的字符不相等,则需要找到前一个位置的最长匹配前后缀,并将当前位置的部分匹配值更新为最长匹配前后缀的长度。

这是通过比较当前位置字符与前一个位置的最长匹配前后缀的下一个字符来实现的,直到找到最长匹配前后缀或者无法再找到为止。

利用部分匹配表,KMP算法可以在匹配过程中避免进行不必要的回溯。

具体的匹配过程如下:1.设置文本串的索引i和模式串的索引j,两者都从0开始;2.对比文本串的第i位和模式串的第j位进行字符比较;3.如果匹配成功,将i和j都加1;4.如果不匹配,则利用部分匹配表来确定模式串的下一个比较位置。

具体来说,如果j大于0,则将j更新为部分匹配表中j-1位置的部分匹配值,然后再与i进行比较;如果j等于0,则将i加15.重复步骤2到步骤4,直到模式串匹配成功或者遍历完文本串。

kmp算法报告

kmp算法报告

KMP算法报告●算法思想KMP算法是基于BF算法的低效率进行改进的,因此在介绍KMP算法之前先让我们来了解BF算法。

BF的思想是直截了当的:将主串S中某个位置i起始的子串和模式串T相比较。

即从j=0 起比较S[i+j] 与T[j],若相等,则在主串S 中存在以i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与T串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的"匹配",即将串T向后滑动一位,即i 增1,而j 退回至0,重新开始新一轮的匹配。

KMP算法先根据已经部分匹配的信息,将匹配的指针跳过不必匹配的位置。

在KMP算法中,对于每一个模式串我们会事先计算出模式串的内部匹配信息,在匹配失败时最大的移动模式串,以减少匹配次数。

比如,在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。

右移的距离在KMP算法中是如此计算的:在已经匹配的模式串子串中,找出最长的相同的前缀和后缀,然后移动使它们重叠。

●算法步骤Step1:分别指示主串、模式串比较位置的指针i,j 初始化。

Step2:重复下列操作,直至S中所剩字符个数小于T的长度或T中所有字符均比较完。

2.1 如果si=tj, i和j 分别增一;否则;2.2 j=next[j]2.3 如果 j=0,则将i 和j 分别加一。

Step3:如果T中所有字符均比较完,则反回匹配的起始下标;否则,返回-1.●算法实现#include <iostream>#include <cstring>using namespace std;void getNext(const char* pattern,int next[]){next[0]= -1;int k=-1,j=0;while(pattern[j] != '\0'){if(k!= -1 && pattern[k]!= pattern[j] )k=next[k];++j;++k;if(pattern[k]== pattern[j])next[j]=next[k];elsenext[j]=k;}//这里是我加的显示部分// for(int i=0;i<j;i++)//{// cout<<next[i];//}//cout<<endl;}int KMP(const char *Text,const char* Pattern)//const 表示函数内部不会改变这个参数的值。

KMP算法详解

KMP算法详解

KMP算法详解KMP 算法详解KMP 算法是⼀个⼗分⾼效的字符串查找算法,⽬的是在⼀个字符串 s 中,查询 s 是否包含⼦字符串 p,若包含,则返回 p 在 s 中起点的下标。

KMP 算法全称为 Knuth-Morris-Pratt 算法,由 Knuth 和 Pratt 在1974年构思,同年 Morris 也独⽴地设计出该算法,最终由三⼈于1977年联合发表。

举⼀个简单的例⼦,在字符串 s = ababcabababca 中查找⼦字符串 p = abababca,如果暴⼒查找,我们会遍历 s 中的每⼀个字符,若 s[i] = p[0],则向后查询p.length() 位是否都相等。

这种朴素的暴⼒的算法复杂度为O(m×n),其中m和n分别是 p 和 s 的长度。

KMP 算法可以⽅便地简化这⼀查询的时间复杂度,达到O(m+n)。

1. PMT 序列PMT 序列是 KMP 算法的核⼼,即 Partial Match Table(部分匹配表)。

举个例⼦:char a b a b a b c aindex01234567PMT00123401PMT 的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。

PMT[0] = 0: 字符串 a 既没有前缀,也没有后缀;PMT[1] = 0: 字符串 ab 前缀集合为 {a},后缀集合为 {b},没有交集;PMT[2] = 1: 字符串 aba 前缀集合为 {a, ab},后缀集合为 {ba, a},交集为 {a},交集元素的最长长度为1;PMT[3] = 2: 字符串 abab 前缀集合为 {a, ab, aba},后缀集合为 {bab, ab, b},交集为 {ab},交集元素的最长长度为2;…… 以此类推。

2. 算法主体现在我们已经知道了 PMT 序列的含义,那么假设在 PMT 序列已经给定的情况下,如何加速字符串匹配算法?tar 存储 s 的下标,从 0 开始,若 tar > s.length() - 1,代表匹配失败;pos 存储 p 的下标,从 0 开始,若 s[tar] != p[pos],则 pos ⾛到下⼀个可能匹配的位置。

KMP算法

KMP算法

KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法。

但是相较于其他模式匹配算法,该算法晦涩难懂,第一次接触该算法的读者往往会看得一头雾水,主要原因是KMP算法在构造跳转表next过程中进行了多个层面的优化和抽象,使得KMP算法进行模式匹配的原理显得不那么直白。

本文希望能够深入KMP算法,将该算法的各个细节彻底讲透,扫除读者对该算法的困扰。

KMP算法对于朴素匹配算法的改进是引入了一个跳转表next[]。

以模式字符串abcabcacab为例,其跳转表为:举例说明,如下是使用上例的模式串对目标串执行匹配的步骤next跳转表,在进行模式匹配,实现模式串向后移动的过程中,发挥了重要作用。

这个表看似神奇,实际从原理上讲并不复杂,对于模式串而言,其前缀字符串,有可能也是模式串中的非前缀子串,这个问题我称之为前缀包含问题。

以模式串abcabcacab为例,其前缀4 abca,正好也是模式串的一个子串abc(abca)cab,所以当目标串与模式串执行匹配的过程中,如果直到第8个字符才匹配失败,同时也意味着目标串当前字符之前的4个字符,与模式串的前4个字符是相同的,所以当模式串向后移动的时候,可以直接将模式串的第5个字符与当前字符对齐,执行比较,这样就实现了模式串一次性向前跳跃多个字符。

所以next表的关键就是解决模式串的前缀包含。

当然为了保证程序的正确性,对于next表的值,还有一些限制条件,后面会逐一说明。

如何以较小的代价计算KMP算法中所用到的跳转表next,是算法的核心问题。

这里我们引入一个概念f(j),其含义是,对于模式串的第j个字符pattern[j],f(j)是所有满足使pattern[1...k-1] = pattern[j-(k-1)...j - 1](k < j)成立的k的最大值。

KMP算法解析范文

KMP算法解析范文

KMP算法解析范文KMP算法的核心是构建一个部分匹配表(Partial Match Table),用来记录已匹配字符串的前缀和后缀的最长公共部分。

这样,在匹配过程中,当出现不匹配的字符时,就可以利用部分匹配表的信息来调整匹配的位置,而不是回溯所有已匹配的字符。

为了方便理解KMP算法的原理,我们首先从部分匹配表的构建开始。

假设待匹配的字符串为P,原字符串为T。

1.部分匹配表的定义:部分匹配表是一个长度为P.length的数组,记为next[],其中next[i]表示长度为i的前缀子串(不包含最后一个字符)和后缀子串(不包含第一个字符)的最长公共部分的长度。

2.部分匹配表的构建:首先,next[0]被定义为-1,next[1]被定义为0。

然后,从i=2开始,依次计算next[i]的值。

(1)假设next[i-1]的值已经求得,即长度为i-1的前缀子串和后缀子串的最长公共部分的长度为next[i-1]。

(2)将P的前缀子串P[0:i-1]和后缀子串P[1:i-1]的长度都加1,得到长度为i的前缀子串和后缀子串。

分别记为P[0:i]和P[1:i]。

(3)比较P[0:i]和P[1:i],找到最长的公共部分。

如果存在公共部分,则next[i]取公共部分的长度;否则,next[i]取0。

其中,比较的方法是利用已经求得的next[i-1]和P[i-1]来确定比较的位置。

具体而言,如果P[i-1]与P[next[i-1]]相等,则next[i]等于next[i-1]加1;否则,需要继续往前寻找可能的公共部分,即比较P[i-1]和P[next[next[i-1]]],直到找到公共部分或者找到P的开头。

3.KMP算法的匹配过程:假设待匹配的字符串为P,原字符串为T,分别用变量i和j表示匹配过程中的位置。

(1)初始化i=0和j=0。

(2)比较P[i]和T[j]。

如果相等,则继续比较下一个字符;如果不相等,则根据部分匹配表调整i和j的值。

动态规划之KMP算法详解

动态规划之KMP算法详解

动态规划之KMP算法详解KMP 算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,效率很高,但是确实有点复杂。

很多读者抱怨 KMP 算法无法理解,这很正常,想到大学教材上关于KMP 算法的讲解,也不知道有多少未来的Knuth、Morris、Pratt 被提前劝退了。

有一些优秀的同学通过手推 KMP 算法的过程来辅助理解该算法,这是一种办法,不过本文要从逻辑层面帮助读者理解算法的原理。

十行代码之间,KMP 灰飞烟灭。

先在开头约定,本文用pat表示模式串,长度为M,txt表示文本串,长度为N。

KMP 算法是在txt中查找子串pat,如果存在,返回这个子串的起始索引,否则返回 -1。

为什么我认为 KMP 算法就是个动态规划问题呢,等会有解释。

对于动态规划,之前多次强调了要明确dp数组的含义,而且同一个问题可能有不止一种定义dp数组含义的方法,不同的定义会有不同的解法。

读者见过的 KMP 算法应该是,一波诡异的操作处理pat后形成一个一维的数组next,然后根据这个数组经过又一波复杂操作去匹配txt。

时间复杂度 O(N),空间复杂度 O(M)。

其实它这个next数组就相当于dp数组,其中元素的含义跟pat的前缀和后缀有关,判定规则比较复杂,不太好理解。

本文则用一个二维的dp数组(但空间复杂度还是O(M)),重新定义其中元素的含义,使得代码长度大大减少,可解释性大大提高。

PS:本文的代码参考《算法4》,原代码使用的数组名称是dfa (确定有限状态机),因为我们的公众号之前有一系列动态规划的文章,就不说这么高大上的名词了,本文还是沿用dp数组的名称。

一、KMP 算法概述首先还是简单介绍一下 KMP 算法和暴力匹配算法的不同在哪里,难点在哪里,和动态规划有啥关系。

暴力的字符串匹配算法很容易写,看一下它的运行逻辑:// 暴力匹配(伪码)int search(String pat, String txt) {int M = pat.length;int N = txt.length;for (int i = 0; i < N - M; i++) {int j;for (j = 0; j < M; j++) {if (pat[j] != txt[i+j])break;}// pat 全都匹配了if (j == M) return i;}// txt 中不存在 pat 子串return -1;}对于暴力算法,如果出现不匹配字符,同时回退txt和pat的指针,嵌套 for 循环,时间复杂度 O(MN),空间复杂度O(1)。

kmp百度百科

kmp百度百科

kmp算法[编辑本段]kmp算法-概述一种改进的字符串匹配算法,由 D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。

[编辑本段]kmp算法-学习介绍完全掌握KMP算法思想学过数据结构的人,都对KMP算法印象颇深。

尤其是新手,更是难以理解其涵义,搞得一头雾水。

今天我们就来面对它,不将它彻底搞懂,誓不罢休。

如今,大伙基本上都用严蔚敏老师的书,那我就以此来讲解KMP 算法。

(小弟正在备战考研,为了节省时间,很多课本上的话我都在此省略了,以后一定补上。

)严老的《数据结构》79页讲了基本的匹配方法,这是基础。

先把这个搞懂了。

80页在讲KMP算法的开始先举了个例子,让我们对KMP的基本思想有了最初的认识。

目的在于指出“由此,在整个匹配的过程中,i指针没有回溯,”。

我们继续往下看:现在讨论一般情况。

假设主串:s: ‘s(1) s(2) s(3) ……s(n)’; 模式串:p: ‘p(1) p(2) p(3)…..p(m)’把课本上的这一段看完后,继续现在我们假设主串第i个字符与模式串的第j(j<=m)个字符‘失配’后,主串第i个字符与模式串的第k(k<j)个字符继续比较此时,s(i)≠p(j), 有主串:S(1)……s(i-j+1)……s(i-1) s(i) ………….|| (相配) || ≠(失配)匹配串:P(1) ……. p(j-1) p(j)由此,我们得到关系式‘p(1) p(2) p(3)…..p(j-1)’= ’s(i-j+1)……s(i-1)’由于s(i)≠p(j),接下来s(i)将与p(k)继续比较,则模式串中的前(k-1)个字符的子串必须满足下列关系式,并且不可能存在k’>k 满足下列关系式:(k<j),‘p(1) p(2) p(3)…..p(k-1)’= ’s(i-k+1)s(i-k+2)……s(i-1)’即:主串:S(1)……s(i-k +1) s(i-k +2) ……s(i-1) s(i) ………….|| (相配) || || ?(有待比较)匹配串:P(1) p(2) ……p(k-1) p(k)现在我们把前面总结的关系综合一下有:S(1)…s(i-j +1)…s(i-k +1) s(i-k +2) ……s(i-1) s(i) ……|| (相配) || || || ≠(失配)P(1) ……p(j-k+1) p(j-k+2) ….... p(j-1) p(j)|| (相配) || || ?(有待比较)P(1) p(2) ……. p(k-1) p(k)由上,我们得到关系:‘p(1) p(2) p(3)…..p(k-1)’= ’s(j-k+1)s(j-k+2)……s(j-1)’接下来看“反之,若模式串中存在满足式(4-4)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

文献综述
一般使用的计算机的硬件结构主要反映数值计算的需要,而计算机上的非数值处理的对象基本上是字符串数据,因此在处理字符串数据时比处理整数和浮点数要复杂的很多。

随着程序语言将程序的发展,字符串的处理也有了越来越多的研究。

子串的定位炒作通常称为串的模式匹配,是各种处理系统中最重要的操作之一。

串匹配问题是指从给定的字符序列中找出一个或多个具有某种属性的模式序列,而字符串匹配指的便是从给定的字符序列中找出一个或若干个给定的字符串。

字符串匹配算法是一个基础算法,它的解决以及在这个过程中产生的方法对计算机的其他问题都产生了巨大的影响。

在我们日常使用计算机的过程中,使用字符串匹配技术的例子十分普遍,例如:入侵检测、病毒检测、信息检索、信息过滤、计算生物学等等都包含了字符串匹配技术。

在字符串匹配技术被广泛应用的同时,众多的科技人员也对其进行了深入的研究,字符串匹配问题现在已经发展成为一门相对独立的科学——字符串学(Stingology)[1][2][3]。

字符串匹配技术最先被应用于图书文献目录摘要的查询系统和构建数据的全文检索系统。

而后,随着网络安全技术和生物技术的日益发展,在网络安全和生物计算等领域中字符串匹配技术又获得了新的发展空间。

随着网络速度和流量的日益增加,基于网络的入侵检测[4][5]系统面临着严峻的挑战,它的处理、分析速度越来越难以跟上网络流量增加速度,从而极易导致数据包的丢失。

解决数据包丢失等问题,提高处理速度是关键。

另外对于基于误用的入侵检测系统而言,检测过程中最费时的部分便是入侵特征匹配。

目前,信息资源的高速膨胀已经成为一个全球普遍关注的现象。

加利福尼亚大学伯克利分校研究人员发现,仅从1999年至2002年全球新产生的信息量就翻了一番。

伴随着信息膨胀,信息的良莠不齐现象也是一个严重困扰人们的问题。

大量反动、黄色信息以及国家机密在网络上蔓延和传播,给国建安全和社会稳定造成了严重的威胁,如何对这些不良信息进行网络监控是我们面临的一个重要问题。

在信息过滤时,特别是在主干网络上进行过滤与检索,对字符串匹配的实时性要求极高,字符串匹配性能的优劣直接影响了过滤与检索系统的性能。

随着生命科学的发展,人们对生命物质的微观结构也有了越来越清晰的认识。

目前,人类基因组序列的绘制工作已完成,Prosite等大型蛋白质重要样本数
据库已经建立[6]。

由于基因和蛋白质都可以用建立在一定字符集上的符号序列来表示,因此字符串匹配技术变有了新的发展空间。

在计算生物学中,海量的基因组序列数据和蛋白质序列数据中进行比对、分析、组合的基本是字符串匹配技术。

综上所述,随后则计算机技术和网络技术的发展,模式匹配算法的重要性越发突出,研究设计高效率的匹配算法这是计算机技术发展的迫切需求,为了在最快的时间内研究设计出高效的匹配算法,我们必须学习和借鉴一些经典的算法,其中KMP算法最具有代表性,在最坏的情况下它能保证在O(n+m)的时间数量级上完成串的模式匹配操作。

KMP算法的最大特点是指示主串的指针不须回溯,整个匹配过程中,对主串仅需从头到尾扫描一遍,这对处理从外设输入的庞大文件很有效,可以边度入边匹配,而无需回头重读。

它的这些优点使其成为经典算法之一,而其算法的衍生算法数量也极其庞大,所以我们很有必要对其学习研究。

参考文献
[1]严蔚敏,吴伟民.数据结构(C语言版) [M].北京:清华大学出版社,2008.9
[2]刘燕兵.串匹配算法优化的研究.中国科学院硕士学位论文-中国科学院计算技术研究所,2006.6
[3]潘金贵,顾铁成.算法导论.[M].机械工业出版社,2010.9
[4]吴哲辉,曹立明,蒋昌俊.算法分析与设计[M].北京:煤炭工业出版社,2006.6。

相关文档
最新文档