kmp算法课件演示(推荐)

合集下载

kmp算法原理

kmp算法原理

kmp算法原理KMP算法(Knuth-Morris-Pratt算法)是一种用于快速搜索字符串中某个模式字符串出现位置的算法,由Knuth, Morris 和 Pratt于1977年提出。

KMP算法的工作方式如下:首先,给定一个主串S和一个模式串P,KMP算法的第一步就是先构造一个新的模式串P,其中的每一项存储着P中每一个字符前面由不同字符串组成的最长前缀和最长后缀相同的子串。

接着,在S中寻找P,它会从S的第一个字符开始,如果匹配上,就继续比较下一个字符,如果不匹配上,就根据P中相应位置上保存的信息跳到特定位置,接着再开始比较,如此不断循环下去,直到从S中找到P为止。

KMP算法的思路特别巧妙,比较效率很高,它的复杂度为O(m+n),其中m为主串的长度,n为模式串的长度。

它取代了以前的暴力搜索算法,极大地提高了程序的性能。

KMP算法的实现过程如下:(1)首先确定模式串P的每一个字符,构造模式串P的next数组:next[i]存储P中第i个字符之前最长相同前缀和后缀的长度(P中第i个字符之前最长相同前缀和后缀不包括第i个字符);(2)接着从S中的第一个字符开始比较P中的每一个字符,如果字符不匹配,则采用next数组中保存的信息跳到特定位置,而不是暴力比较,以此不断循环,直到从S中找到P为止。

KMP算法是由Don Knuth, Vaughan Pratt和James Morris在1977年提出的。

它的思想是利用之前遍历过的P的信息,跳过暴力比较,可以把字符串搜索时间从O(m×n)降低到O(m+n)。

KMP算法在很多领域有着重要的应用,如文本编辑,模式匹配,编译器设计与多项式字符串匹配等等,都是不可或缺的。

kmp

kmp

2 KMP算法:KMP算法是由D.E.Knuth(克努特),J.H.Morris(莫里斯),V.R.Pratt(普拉特)等人共同提出的,该算法主要消除了主串指针(i指针)的回溯,利用已经得到的部分匹配结果将模式串右滑尽可能远的一段距离再继续比较,从而使算法效率有某种程度的提高,O(n+m)。

先从例子入手(p82):按Brute-Force算法i=i-j+2=2-2+2=2,j=1按Brute-Force算法i=i-j+2=2-1+2=3,j=1按Brute-Force算法i=i-j+2=8-6+2=4,j=1,但从已匹配的情况看,模式串在t[6]即“c”前的字符都是匹配的,再看已匹配的串“abaab”,t[1]t[2]与t[4]t[5]相同,那么,因为t[4]t[5]与原串s[6]s[7]匹配,所以t[1]t[2]必然与原串s[6]s[7]匹配,因此说t[3]可以直接与s[8]匹配,按KMP 算法i=8,j=3匹配成功。

从上例看出在匹配不成功时,主串指针i不动,j指针也不回到第一个位置,而是回到一个恰当的位置,如果这时让j指针回到第一个位置,就可能错过有效的匹配,所以在主串指针i不动的前提下,j指针回到哪个位置是问题的关键,既不能将j右移太大,而错过有效的匹配,另一方面,又要利用成功的匹配,将j右移尽可能地大,而提高匹配的效率,因此问题的关键是寻找模式串自身的规律。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////。

和直接比较若不满足和直接比较所以:满足:,设1i i 12112111112121s ),2(;s )1(""")"2(""")"1(""""t t j k t t t t t t t t s s t t t t s s s s k j k j k j k j i j i m n <<====-+-+----+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////设s=” s 1 s 2 ... s n ”, t=” t 1 t 2 ... t m ”,在匹配过程中,当s i ≠ t j (1≤i ≤n-m+1,1≤j ≤m)时,存在(前面的j-1个字符已匹配):” s i-j+1 ... s i-1 ” =” t 1 t 2 ... t j-1 ” (1) 若模式中存在可互相重叠的最长的真子串,满足: ” t 1 t 2 ... t k-1 ”=”t j-k+1 t j-k+2 ... t j-1 ” (2) 其中真子串最短可以是t 1 ,即 t 1。

实验04:串应用KMP算法PPT课件

实验04:串应用KMP算法PPT课件

在生物信息学中的应用
在生物信息学中,KMP算法被广泛应用于基因序列的比对和拼接,以及蛋白质序列 的匹配和比对。
通过构建基因序列或蛋白质序列的索引表,KMP算法可以在O(n+m)的时间复杂度 内完成序列的比对和拼接,提高了比对和拼接的准确性和效率。
KMP算法在生物信息学中的应用有助于深入了解基因和蛋白质的结构和功能,为生 物医学研究和疾病诊断提供了有力支持。
06 实验总结与展望
KMP算法的优缺点
优点
高效:KMP算法在匹配失败时能跳过 尽可能多的字符,减少比较次数,从
而提高匹配效率。
适用范围广:KMP算法适用于各种模 式串匹配问题,不受模式串长度的限 制。
缺点
计算量大:KMP算法需要计算和存储 部分匹配表,对于较长的模式串,计 算量较大。
不适合处理大量数据:KMP算法在处 理大量数据时可能会占用较多内存, 导致性能下降。
匹配失败的处理
当模式串中的某个字符与主串中的对应字符不匹配时,模式串向右 滑动,与主串的下一个字符重新对齐,继续比较
next[ j]表示当模式串中第j个字符与主 串中的对应字符不匹配时,模式串需 要向右滑动的位置。
next数组的构建
next数组的作用
在匹配过程中,通过next数组可以快 速确定模式串需要滑动到哪个位置, 从而提高了匹配效率。
通过已知的next值,递推计算出next 数组中其他位置的值。
KMP算法的时间复杂度
01
02
03
04
时间复杂度分析
KMP算法的时间复杂度取决 于模式串在主串中出现的次数 以及每次匹配所花费的时间。
最佳情况
当模式串在主串中连续出现时 ,KMP算法的时间复杂度为

BF算法KMP算法BM算法

BF算法KMP算法BM算法

BF算法KMP算法BM算法BF算法(Brute-Force算法)是一种简单直接的字符串匹配算法。

它的基本思想是从主串的第一个字符开始,逐个与模式串的字符进行比较,如果匹配失败,则主串的指针向右移动一位,继续从下一个字符开始匹配。

重复这个过程,直到找到匹配的子串或者主串遍历完毕。

BF算法的时间复杂度是O(n*m),其中n和m分别是主串和模式串的长度。

当模式串较长时,算法的效率较低。

但是BF算法的实现简单,易于理解,对于较短的模式串和主串,仍然是一种可行的匹配算法。

KMP算法(Knuth-Morris-Pratt算法)是一种改进的字符串匹配算法,它利用了模式串内部的信息,避免了不必要的比较。

KMP算法引入了一个next数组,用于记录模式串中每个位置对应的最长可匹配前缀子串的长度。

KMP算法的基本思想是,当匹配失败时,不是简单地将主串指针右移一位,而是利用next数组将模式串的指针向右移动若干位,使得主串和模式串中已经匹配的部分保持一致,减少比较次数。

通过预处理模式串,计算出next数组,可以在O(n+m)的时间复杂度内完成匹配。

BM算法(Boyer-Moore算法)是一种高效的字符串匹配算法,它结合了坏字符规则和好后缀规则。

BM算法从模式串的末尾开始匹配,根据坏字符规则,如果在匹配过程中发现了不匹配的字符,可以直接将模式串向右滑动到该字符在模式串中最右出现的位置。

BM算法还利用了好后缀规则,当发现坏字符后,可以根据好后缀的位置和模式串的后缀子串进行匹配,从而减少不必要的比较。

通过预处理模式串,计算出坏字符规则和好后缀规则对应的滑动距离,可以在最坏情况下实现O(n/m)的时间复杂度。

总结来说,BF算法是一种简单直接的字符串匹配算法,适用于较短的模式串和主串;KMP算法通过预处理模式串,利用next数组减少比较次数,提高了匹配效率;BM算法结合了坏字符规则和好后缀规则,利用了更多的信息,是一种高效的字符串匹配算法。

KMP算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)KMP算法以及优化(代码分析以及求解next数组和nextval数组)来了,数据结构及算法的内容来了,这才是我们的专攻,前⾯写的都是开胃⼩菜,本篇⽂章,侧重考研408⽅向,所以保证了你只要看懂了,题⼀定会做,难道这样思想还会不会么?如果只想看next数组以及nextval数组的求解可以直接跳到相应部分,思想总结的很⼲~~⽹上的next数组版本解惑先总结⼀下,⼀般KMP算法的next数组结果有两个版本,我们需要知道为什么会存在这种问题,其实就是前缀和后缀没有匹配的时候next数组为0还是为1,两个版本当然都是对的了,如果next数组为0是的版本,那么对于前缀和后缀的最⼤匹配长度只需要值+1就跟next数组是1的版本⼀样了,其实是因为他们的源代码不⼀样,或者对于模式串的第⼀个下标理解为0或者1,总之这个问题不⽤纠结,懂原理就⾏~~那么此处,我们假定前缀和后缀的最⼤匹配长度为0时,next数组值为1的版本,考研⼀般都是⽤这个版本(如果为0版本,所有的内容-1即可,如你算出next[5]=6,那么-1版本的next[5]就为5,反之亦然)~~其实上⾯的话总结就是⼀句话next[1]=0,j(模式串)数组的第⼀位下标为1,同时,前缀和后缀的最⼤匹配长度+1即为next数组的值,j所代表的的是序号的意思408反⼈类,⼀般数组第⼀位下标为1,关于书本上前⾯链表的学习⼤家就应该有⽬共睹了,书本上好多数组的第⼀位下标为了⽅便我们理解下标为1,想法这样我们更不好理解了,很反⼈类,所以这⾥给出next[1]=0,前缀和后缀的最⼤匹配长度+1的版本讲解前⾔以及问题引出我们先要知道,KMP算法是⽤于字符串匹配的~~例如:⼀个主串"abababcdef"我们想要知道在其中是否包括⼀个模式串"ababc"初代的解决⽅法是,朴素模式匹配算法,也就是我们主串和模式串对⽐,不同主串就往前移⼀位,从下⼀位开始再和模式串对⽐,每次只移动⼀位,这样会很慢,所以就有三位⼤神⼀起搞了个算法,也就是我们现在所称的KMP算法~~代码以及理解源码这⾥给出~~int Index_KMP(SString S,SString T,intt next[]){int i = 1,j = 1;//数组第⼀位下标为1while (i &lt;= S.length &amp;&amp; j &lt;= T.length){if (j == 0 || S.ch[i] == T.ch[j]){//数组第⼀位下标为1,0的意思为数组第⼀位的前⾯,此时++1,则指向数组的第⼀位元素++i;++j; //继续⽐较后继字符}elsej = next[j]; //模式串向右移动到第⼏个下标,序号(第⼀位从1开始)}if (j &gt; T.length)return i - T.length; //匹配成功elsereturn 0;}接下来就可以跟我来理解这个代码~~还不会做动图,这⾥就⼿画了~~以上是⼀般情况,那么如何理解j=next[1]=0的时候呢?是的,这就是代码的思路,那么这时我们就知道,核⼼就是要求next数组各个的值,对吧,⼀般也就是考我们next数组的值为多少~~next数组的求解这⾥先需要给出概念,串的前缀以及串的后缀~~串的前缀:包含第⼀个字符,且不包含最后⼀个字符的⼦串串的后缀:包含最后⼀个字符,且不包含第⼀个字符的⼦串当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1与此同时,next[1]=0如,模式串"ababaa"序号J123456模式串a b a b a anext[j]0当第六个字符串匹配失败,那么我们需要在前5个字符组成的串S"ababa"中找最长相等的前后缀长度为多少再+1~~如串S的前缀可以为:"a","ab","aba","abab",前缀只不包括最后⼀位都可串S的后缀可以为:"a","ba","aba","baba",后缀只不包括第⼀位都可所以这⾥最⼤匹配串就是"aba"长度为3,那么我们+1,取4序号J123456模式串a b a b a anext[j]04再⽐如,当第⼆个字符串匹配失败,由前1个字符组成的串S"a"中,我们知道前缀应当没有,后缀应当没有,所以最⼤匹配串应该为0,那么+1就是取1~~其实这⾥我们就能知道⼀个规律了,next[1]⼀定为0(源码所造成),next[2]⼀定为1(必定没有最⼤匹配串造成)~~序号J123456模式串a b a b a anext[j]014再再⽐如,第三个字符串匹配失败,由前两个字符组成的串S"ab"中找最长相等的前后缀长度,之后再+1~~前缀:"a"后缀:"b"所以所以这⾥最⼤匹配串也是没有的长度为0,那么我们+1,取1序号J123456模式串a b a b a anext[j]0114接下来你可以⾃⼰练练4和5的情况~~next[j]011234是不是很简单呢?⾄此,next数组的求法以及kmp代码的理解就ok了~~那么接下来,在了解以上之后,我们想⼀想KMP算法存在的问题~~KMP算法存在的问题如下主串:"abcababaa"模式串:"ababaa"例如这个问题我们很容易能求出next数组序号J123456模式串a b a b a anext[j]011234此时我们是第三个字符串匹配失败,所以我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,可是我们刚开始的时候就已经知道模式串的第三个字符"a"和"c"不匹配,那么这⾥不就多了⼀步⽆意义的匹配了么?所以我们就会有kmp算法的⼀个优化了~~KMP算法的优化我们知道,模式串第三个字符"a"不和主串第三个字符"c"不匹配,next数组需要我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,之后就是模式串第⼀个字符"a"不和"c"匹配,就是需要变为next[1]=0,那么我们要省去步骤,不就可以直接让next[3]=0么?序号J12345模式串a b a b anext[j]01123nextval[j]00那么怎么省去多余的步骤呢?这就是nextval数组的求法~~nextval的求法以及代码理解先贴出代码for (int j = 2;j &lt;= T.length;j++){if (T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];}如序号J123456模式串a b a b a anext[j]011234nextval[j]0⾸先,第⼀次for循环,j=2,当前序号b的next[2]为1,即第⼀个序号所指向的字符a,a!=当前序号b,所以nextval[2]保持不变等于next[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]01第⼆次for循环,j=3,当前序号a的next[3]为1,即第⼀个序号所指向的字符a,a=当前序号a,所以nextval[3]等于nextval[1]=0序号J123456模式串a b a b a anext[j]011234nextval[j]010第三次for循环,j=4,当前序号b的next[4]为2,即第⼆个序号所指向的字符b,b=当前序号b,所以nextval[4]等于nextval[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]0101就是这样,你可以练练5和6,这⾥直接给出~~序号J123456模式串a b a b a anext[j]011234nextval[j]010104⾄此nextval数组的求法你也应该会了,那么考研要是考了,那么是不是就等于送分给你呢?⼩练习那么你试着来求⼀下这个模式串的next和nextval数组吧~~next[j]nextval[j]⼩练习的答案序号j12345模式串a a a a b next[j]01234 nextval[j]00004。

严蔚敏 数据结构 kmp算法详解

严蔚敏 数据结构 kmp算法详解
max{k|0<k<j,且“t0t1…tk-1”=“tj-ktj-k+1…tj-1” }
当此集合非空时
next[j]= -1 0 当j=0时 其他情况
t=“abab”对应的next数组如下:
j t[j] next[j] 0 a -1 1 b 0 2 a 0 3 b 1
void GetNext(SqString t,int next[]) { int j,k; j=0;k=-1;next[0]=-1; while (j<t.len-1)
既然如此,回溯到si-j+1开始与t匹配可以不做。那 么,回溯到si-j+2 开始与t匹配又怎么样?从上面推理 可知,如果 "t0t1…tj-2"≠"t2t3…tj"
仍然有
"t0t1…tj-2"≠"si-j+2si-j+3…si"
这样的比较仍然“失配”。依此类推,直到对于 某一个值k,使得: "t0t1…tk-2"≠" tj-k+1tj-k+2…tj-1"
b 3
第 1 次匹配
第 2 次匹配
s=aaabaaaa b t=aaaab
第 3 次匹配
s=aaabaaaa b t=aaaab
第 4 次匹配
s=aaabaaaa b t=aaaab
第 5 次匹配
s=aaabaaaa b t=aaaab
上述定义的next[]在某些情况下尚有缺陷。 例如,模式“aaaab”在和主串“aaabaaaab”匹配时, 当i=3,j=3时,s.data[3]≠t.data[3],由next[j]的指示还需 进行i=3、j=2,i=3、j=1,i=3、j=0等三次比较。实际上, 因为模式中的第1、2、3个字符和第4个字符都相等, 因此,不需要再和主串中第4个字符相比较,而可以将模 式一次向右滑动4个字符的位置直接进行i=4,j=0时的 字符比较。

KMP算法(改进的模式匹配算法)——next函数

KMP算法(改进的模式匹配算法)——next函数

KMP算法(改进的模式匹配算法)——next函数KMP算法简介KMP算法是在基础的模式匹配算法的基础上进⾏改进得到的算法,改进之处在于:每当匹配过程中出现相⽐较的字符不相等时,不需要回退主串的字符位置指针,⽽是利⽤已经得到的部分匹配结果将模式串向右“滑动”尽可能远的距离,再继续进⾏⽐较。

在KMP算法中,依据模式串的next函数值实现字串的滑动,本随笔介绍next函数值如何求解。

next[ j ]求解将 j-1 对应的串与next[ j-1 ]对应的串进⾏⽐较,若相等,则next[ j ]=next[ j-1 ]+1;若不相等,则将 j-1 对应的串与next[ next[ j-1 ]]对应的串进⾏⽐较,⼀直重复直到相等,若都不相等则为其他情况题1在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。

若模式串p 为“abaac”,则其next函数值为()。

解:j=1,由式⼦得出next[1]=0;j=2,由式⼦可知1<k<2,不存在k,所以为其他情况即next[2]=1;j=3,j-1=2 对应的串为b,next[2]=1,对应的串为a,b≠a,那么将与next[next[2]]=0对应的串进⾏⽐较,0没有对应的串,所以为其他情况,也即next[3]=1;j=4,j-1=3 对应的串为a,next[3]=1,对应的串为a,a=a,所以next[4]=next[3]+1=2;j=5,j-1=4 对应的串为a,next[4]=2,对应的串为b,a≠b,那么将与next[next[4]]=1对应的串进⾏⽐较,1对应的串为a,a=a,所以next[5]=next[2]+1=2;综上,next函数值为 01122。

题2在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。

若模式串p为“tttfttt”,则其next函数值为()。

不同的模式匹配方法详解(暴力、KMP、Rabin-Karp算法)

不同的模式匹配方法详解(暴力、KMP、Rabin-Karp算法)

不同的模式匹配⽅法详解(暴⼒、KMP、Rabin-Karp算法)1 概述单模式匹配是处理字符串的经典问题,指在给定字符串中寻找是否含有某⼀给定的字串。

⽐较形象的是CPP中的strStr()函数,Java的String 类下的indexOf()函数都实现了这个功能,本⽂讨论⼏种实现单模式匹配的⽅法,包括暴⼒匹配⽅法、KMP⽅法、以及Rabin-Karp⽅法(虽然Rabin-Karp⽅法在单模式匹配中性能⼀般,单其多模式匹配效率较⾼,且采取⾮直接⽐较的⽅法也值得借鉴)。

算法预处理时间匹配时间暴⼒匹配法O(mn)KMP O(m)O(n)Rabin-Karp O(m)O(mn)2 暴⼒匹配模式匹配类的问题做法都是类似使⽤⼀个匹配的滑动窗⼝,失配时改变移动匹配窗⼝,具体的暴⼒的做法是,两个指针分别指向长串的开始、短串的开始,依次⽐较字符是否相等,当不相等时,指向短串的指针移动,当短串指针已经指向末尾时,完成匹配返回结果。

以leetcode为例给出实现代码(下同)class Solution {public int strStr(String haystack, String needle) {int m = haystack.length(), n = needle.length();if (needle.length() == 0) return 0;for (int i = 0; i <= m - n; i++) {for (int j = 0; j < n; j++) {if (haystack.charAt(i + j) != needle.charAt(j))break;if (j == n - 1)return i;}}return -1;}}值得注意的是,Java中的indexO()⽅法即采⽤了暴⼒匹配⽅法,尽管其算法复杂度⽐起下⾯要谈到的KMP⽅法要⾼上许多。

⼀个可能的解释是,⽇常使⽤此⽅法过程中串的长度都⽐较短,⽽KMP⽅法预处理要⽣成next数组浪费时间。

kmp 压力

kmp 压力

KMP算法简介什么是KMP算法KMP算法(Knuth-Morris-Pratt算法)是一种用于字符串匹配的算法,用于在一个主串中查找一个模式串的出现位置。

它的特点是在匹配失败时,不回溯主串的指针,而是通过利用已经匹配过的信息,将模式串尽量地向后移动,从而提高匹配效率。

KMP算法的原理KMP算法的核心思想是利用模式串自身的特点,通过预处理模式串,构建一个部分匹配表(Partial Match Table),从而在匹配过程中可以根据已匹配的信息来决定下一步的匹配位置。

部分匹配表部分匹配表是一个与模式串对应的数组,用于存储模式串在每个位置上的最长相同前缀后缀的长度。

例如,对于模式串”ABCDABD”,其部分匹配表为:位置部分匹配值0 01 02 03 04 15 26 0KMP算法的匹配过程KMP算法的匹配过程可以简述为以下几个步骤:1.预处理模式串,构建部分匹配表;2.在主串中从左到右逐个字符进行匹配;3.如果当前字符匹配成功,则继续比较下一个字符;4.如果当前字符匹配失败,则根据部分匹配表,将模式串向右移动一定的距离,再次进行匹配;5.重复步骤3和4,直到模式串匹配完毕或者主串匹配完毕。

KMP算法的优势相较于朴素的字符串匹配算法,KMP算法具有以下优势:1.减少了不必要的字符比较次数,提高了匹配效率;2.通过预处理模式串,可以在匹配过程中根据已匹配的信息决定下一步的匹配位置,避免了回溯主串的指针。

KMP算法的应用KMP算法在字符串匹配中有着广泛的应用,例如:1.字符串查找:在一个文本中查找一个子串的出现位置;2.字符串替换:将一个文本中的某个子串替换为另一个字符串;3.DNA序列匹配:在生物信息学中,用于比对DNA序列的相似性。

KMP算法的压力测试为了验证KMP算法的效率和稳定性,我们进行了一系列的压力测试。

测试环境•操作系统:Windows 10•处理器:****************************•内存:16GB测试方法我们使用不同长度的主串和模式串进行匹配,记录下KMP算法的执行时间,并与朴素的字符串匹配算法进行对比。

KMP

KMP

KMP算法
next函数的改进 函数的改进
aaabaaaab aaaa ① ② ③
j=4 j=3 j=2 j=1 i=4
j
12345
模式 a a a a b next[j] 0 1 2 3 4 nextval[j] 0 0 0 0 4
aaa aa a
aaaab i = 5; j = 1
next[j] = k,而pj=pk, , 主串中s 不等时, 则 主串中 i和pj不等时, 不需再和p 进行比较, 不需再和 k进行比较, 而直接和p 而直接和 next[k]进行比 较.
第 1 次匹配 s= cddcdc t=cdc 第 2 次匹配 s= cddcdc t=cdc 第 3 次匹配 s= cddcdc t=cdc 第 4 次匹配 s= cddcdc t=cdc i= 3 j= 3 i= 2 j= 1 i= 3 j= 1 i= 6 j= 3 成功 失败 失败 失败
i = i –j +2; j = 1;
KMP算法
j 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 模式串 a b c a a b b c a b c a a b d a b next[j] 0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2
nextval[j]
0 1 1 0 2 1 3 1 0 1 1 0 2 1 7 0 1
KMP算法
KMP算法的时间复杂度 KMP算法的时间复杂度 设主串s 的长度为n, 模式串t 长度为m, KMP算 n,模式串 m,在 设主串 s 的长度为 n, 模式串 t 长度为 m, 在 KMP 算 法中求next 数组的时间复杂度为 O(m),在后面的匹 法中求 next数组的时间复杂度为 O(m), 在后面的匹 next 数组的时间复杂度为O(m), 配中因主串s的下标不减即不回溯,比较次数可记为 配中因主串s的下标不减即不回溯, n,所以KMP算法总的时间复杂度为O(n+m). n,所以KMP算法总的时间复杂度为O(n+m). 所以KMP算法总的时间复杂度为O(n+m)

KMP算法

KMP算法

KMP算法KMP算法是一种用于字符串匹配的快速算法,全称为Knuth-Morris-Pratt算法,是由Donald Knuth、Vaughan Pratt和James Morris在1977年共同提出的。

该算法的核心思想是通过利用已经匹配过的部分来避免不必要的字符比较,从而提高匹配效率。

1.暴力匹配算法在介绍KMP算法之前,我们先来了解一下暴力匹配算法。

暴力匹配算法,又称为朴素匹配算法,是最基本的匹配方法,它的思想就是从主串的第一个字符开始,逐个比较主串和模式串的字符,直到匹配成功或者主串和模式串的所有字符都比较完毕。

具体算法如下:```暴力匹配(主串S,模式串P):i=0j=0n = length(S)m = length(P)while i < n and j < m:if S[i] == P[j]: // 匹配成功,继续比较下一个字符i++else: // 匹配失败,模式串向后移动一位i=i-j+1j=0if j == m: // 匹配成功return i - jelse: // 匹配失败return -1```暴力匹配算法的时间复杂度为O(n*m),其中n和m分别为主串和模式串的长度。

2.KMP算法的思想KMP算法的关键在于构建一个部分匹配表,通过这个表来确定模式串在匹配失败时应该移动的位置。

部分匹配表的定义如下:对于模式串P的前缀子串P[0:i],如果存在一个真前缀等于真后缀,则称其长度为i的真前缀的真后缀长度为部分匹配值。

假设有一个模式串P,我们定义一个部分匹配表next,其中next[i]表示在P[i]之前的子串(不包括P[i])中,有多大长度的相同前缀后缀。

例如,P="ABCDABD",则next[7]=2,因为在P[7]之前的子串中,"ABD"是长度为3的前缀,也是长度为3的后缀。

构建部分匹配表的算法如下:构建部分匹配表(P):m = length(P)next = [0] * m // 初始化部分匹配表j=0k=-1next[0] = -1while j < m - 1:if k == -1 or P[j] == P[k]: // P[j]表示后缀的单个字符,P[k]表示前缀的单个字符j++k++next[j] = kelse:k = next[k]```构建部分匹配表的时间复杂度为O(m),其中m为模式串的长度。

K M P 算 法 详 解

K M P 算 法 详 解

KMP算法详解(转)此前一天,一位MS的朋友邀我一起去与他讨论快速排序,红黑树,字典树,B树、后缀树,包括KMP算法,唯独在讲解KMP算法的时候,言语磕磕碰碰,我想,原因有二:1、博客内的东西不常回顾,忘了不少;2、便是我对KMP算法的理解还不够彻底,自不用说讲解自如,运用自如了。

所以,特再写本篇文章。

由于此前,个人已经写过关于KMP算法的两篇文章,所以,本文名为:KMP算法之总结篇。

本文分为如下六个部分:第一部分、再次回顾普通的BF算法与KMP算法各自的时间复杂度,并两相对照各自的匹配原理;第二部分、通过我此前第二篇文章的引用,用图从头到尾详细阐述KMP算法中的next数组求法,并运用求得的next数组写出KMP算法的源码;第三部分、KMP算法的两种实现,代码实现一是根据本人关于KMP算法的第二篇文章所写,代码实现二是根据本人的关于KMP算法的第一篇文章所写;第四部分、测试,分别对第三部分的两种实现中next数组的求法进行测试,挖掘其区别之所在;第五部分、KMP完整准确源码,给出KMP算法的准确的完整源码;第六步份、一眼看出字符串的next数组各值,通过几个例子,让读者能根据字符串本身一眼判断出其next数组各值。

力求让此文彻底让读者洞穿此KMP算法,所有原理,来龙去脉,让读者搞个通通透透(注意,本文中第二部分及第三部分的代码实现一的字符串下标i从0开始计算,其它部分如第三部分的代码实现二,第五部分,和第六部分的字符串下标i 皆是从1开始的)。

第一部分、KMP算法初解1、普通字符串匹配BF算法与KMP算法的时间复杂度比较KMP算法是一种线性时间复杂的字符串匹配算法,它是对BF算法(Brute-Force,最基本的字符串匹配算法的)改进。

对于给的原始串S 和模式串P,需要从字符串S中找到字符串P出现的位置的索引。

BF算法的时间复杂度O(strlen(S) * strlen(T)),空间复杂度O(1)。

MPKMP 算法详解

MPKMP 算法详解

MP/KMP 算法详解 [草稿]0 comments 2010/08/22 00:39MP/KMP 算法详解By IfContents∙ 1 Prologue∙ 2 Notations∙ 3 Main Idea∙ 4 MP 算法o 4.1 原理o 4.2 跳转数组的计算o 4.3 另一种表示o 4.4 可是...∙ 5 KMP 算法∙ 6 复杂度分析∙7 KMP 算法的最长停顿∙8 为什么费波拉契串这么神奇∙9 PS∙10 References1 Prologue本篇文章主要针对的是对字符串匹配有兴趣的生物以及被某版本数据结构与算法教材中的 KMP 算法讲解弄得不知所云但与此同时却还难能可贵地保持着旺盛求知欲的不幸生在了错误年代的可怜童鞋,其他生物阅读本文前请慎重考虑因为它可能对您的大脑(如果有)、小脑甚至包括脊髓都造成严重且不可恢复的创伤。

2 Notations下文可能会提到“模式串”、“文本串”、“窗口” 这些词,它们的定义如下,如果这些文字使你头晕,请及时做好救治准备。

模式串、文本串所谓模式串,是指你想要找到(或者得到位置 &etc.)的字符串;而文本串,则是指搜索的目标字符串。

比如说你要在 "lucky dog" 中寻找 "dog" ,那么 "dog" 是模式串,"lucky dog" 则是文本串;而你若要在 "If is a lucky dog" 中寻找 "lucky dog" ,那么 "lucky dog" 便成了模式串, "If is a lucky dog" 则是文本串。

Understand?窗口无论用什么样的搜索算法,在搜索的过程中,总是需要将模式串与文本串进行比较,它们对齐的那部分区域,也就是们关心的那块区域,咱称为窗口。

BF算法KMP算法BM算法

BF算法KMP算法BM算法

BF算法KMP算法BM算法1. BF算法(Brute Force Algorithm)BF算法也称为暴力匹配算法,它是一种最简单直观的字符串匹配算法。

其原理是从目标字符串的第一个字符开始,逐个与模式字符串的字符进行比较,如果匹配失败,则将目标字符串的指针向后移动一位,再继续比较。

直到找到匹配或目标字符串被遍历完。

BF算法的时间复杂度为O(n*m),其中n为目标字符串的长度,m为模式字符串的长度。

在最坏情况下,需要进行n-m+1次比较。

BF算法的优点是实现简单,适用于简单的字符串匹配问题。

但是对于大规模文本的匹配效率较低。

2. KMP算法(Knuth–Morris–Pratt Algorithm)KMP算法是一种改进的字符串匹配算法,通过利用已经匹配的信息来避免不必要的比较。

它首先构建一个部分匹配表(Partial Match Table),用于存储模式字符串每个前缀的最长公共前后缀的长度。

然后通过这个表来指导匹配过程。

KMP算法的核心思想是,当出现不匹配的字符时,通过部分匹配表中的信息,可以将模式字符串向后移动尽可能多的位置,而不是单纯地移动一位。

这样可以大大减少不必要的比较次数,提高匹配效率。

KMP算法的时间复杂度为O(n+m),其中n为目标字符串的长度,m为模式字符串的长度。

在构建部分匹配表时需要O(m)的时间复杂度,匹配过程需要O(n)的时间复杂度。

KMP算法的优点是在大规模文本匹配时效率较高,缺点是算法较为复杂,需要额外的存储空间来存储部分匹配表。

3. BM算法(Boyer-Moore Algorithm)BM算法是一种高效的字符串匹配算法,通过利用不匹配字符的信息来跳过尽可能多的字符,从而减少比较次数。

其核心思想是从模式字符串的末尾开始匹配,并向前移动模式字符串。

BM算法分为坏字符规则和好后缀规则两部分:-坏字符规则:当遇到不匹配的字符时,将模式字符串根据目标字符串中的字符向后移动一位,从而跳过了部分字符的比较。

《KMP 字符串模式匹配算法》教学课例

《KMP 字符串模式匹配算法》教学课例

《KMP字符串模式匹配算法》教学课例程玉胜安庆师范学院计算机与信息学院KMP字符串模式匹配是数据结构课程中一个重要的知识点,也是一个难点(学过KMP 算法的同学100%认为:KMP是数据结构课程中最难的部分)。

为了消除他们对KMP算法学习的恐惧心理,激发他们的学习兴趣,调动其积极性,显得尤为重要。

基于以上,我们根据学生的认知特点和接受水平,对教材内容进行了重新构建,并按照数据结构中“时间复杂度”概念,增加了不同模式匹配算法的运行时间,动态逼真的显示了算法的“时间”性能,获得了较好的教学效果。

一、教学目标知识目标:让学生了解KMP算法应用的普遍性。

如:在目前众多的文字处理软件中得到广泛应用,如Microsoft Word中的“查找”或“替换”操作。

而这种操作实现的机制,同学们特别是计算机专业的学生很少去想过。

能力目标:要求学生体验一个完整的抽象数据类型(ADT)的实现方法和过程,并学会判断、计算算法优劣的方法。

价值目标:消除恐怖的学习心态,让学生感悟数据结构算法实际应用价值,从而激发学习的兴趣,形成积极主动式学习的态度。

二、教材分析使用教材是清华大学严蔚敏教授并由清华大学出版社出版的《数据结构(C语言版)》,该教材难度较大,其实验方法特别是ADT方法在教材中介绍较少,而且KMP算法更是从理论分析的角度介绍了匹配算法和next的计算,自学难度很大;虽然该节知识点属于“**(表示难度较大,可以不讲)”,但是其又是考研的一个热点,所以我们又不得不讲。

三、教学重点、难点教学重点:KMP算法中的next和改进的nextval计算教学难点:KMP算法中如何计算next值四、教具准备卡片:多个字符串,字符串指针强力磁吸:6个五、互动式教学过程教学内容教师活动学生活动目标状态创设情境引入课题目前的众多软件中,“查找”、“替换”等操作实现方法,要求学生举例。

给出一篇word文档完成在上述文档中从当前位置向后查找“计算机”或者向前查找“计算机”字符串的方法。

KMP算法(推导方法及模板)

KMP算法(推导方法及模板)

KMP算法(推导⽅法及模板)介绍克努斯-莫⾥斯-普拉特算法Knuth-Morris-Pratt(简称为KMP算法)可在⼀个主⽂本S内查找⼀个词W的出现位置。

此算法通过运⽤对这个词在不匹配时本⾝就包含⾜够的信息来确定下⼀个匹配将在哪⾥开始的发现,从⽽避免重新检查先前匹配的。

此算法可以在O(n+m)时间数量级上完成串的模式匹配操作,其改进在于:每当⼀趟匹配过程中出现字符⽐较不等时,不需回溯i的指针,⽽是利⽤已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离后,继续进⾏⽐较。

kmp的核⼼之处在于next数组,⽽为了⽅便理解,我先介绍KMP的思想KMP匹配当开始匹配时,如果匹配过程中产⽣“失配”时,指针i(原串的下标)不变,指针j(模式串的下标)退回到next[j] 所指⽰的位置上重新进⾏⽐较,并且当指针j退回⾄零时,指针i和指针j需同时加⼀。

即主串的第i个字符和模式的第⼀个字符不等时,应从主串的第i+1个字符起重新进⾏匹配。

简单来说,就是两个串匹配,如果当前字符相等就⽐较两个字符串的下⼀个字符,如果当前匹配不相等时,就让j(待匹配串的下标)回到next[j] 的位置,因为我们已经知道next数组的作⽤是利⽤已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离,如ababac与abac⽐较时i=4,j=4时不匹配,则利⽤next数组让j=2继续匹配⽽不⽤重新开始。

(⽬前先不⽤管next数组的值时如何得到的,只要明⽩它的作⽤即可,下⾯回介绍)所以我们可以写出kmp的代码int KMP(char str[],char pat[]){int lenstr=strlen(str);int lenpat=strlen(pat);int i=1,j=1;while(i<=lenstr){if(j==0 || str[i]==pat[j]) //匹配成功继续往后匹配++i,++j;elsej=next[j]; //否则根据next数组继续匹配if(j==lenpat) //说明匹配完成return 1;}return 0;}接下来就是关键的求next数组了next数组⾸先,next数组取决于模式串本⾝⽽与相匹配的主串⽆关,我们可以对其递推得到。

KMP算法详解(超级详细)

KMP算法详解(超级详细)

KMP算法详解(超级详细)KMP算法,全称为Knuth-Morris-Pratt算法,是一种用于字符串匹配的快速算法。

它的核心思想是在匹配过程中,当出现不匹配的情况时,利用已经匹配的字符信息,避免进行重复匹配,从而提高匹配效率。

首先,我们需要了解一个重要的概念,"部分匹配值"(partialmatch table),它指的是字符串的前缀和后缀的最长的共有元素的长度。

例如,在字符串"ABCDABD"中,它的部分匹配值是[0, 0, 0, 0, 1, 2, 0]。

接下来,我们来详细了解KMP算法的实现过程:1.首先,针对模式串(被查找的字符串)进行预处理,得到部分匹配表。

-定义两个指针,i和j,分别指向模式串的开头和当前字符。

-初始化部分匹配表,将第一个元素置为0。

-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。

-若匹配,则将部分匹配表的下一个元素置为当前指针位置的下一个元素的值加1,并同时将当前指针和i都自增1-若不匹配且i>0,则将i更新为部分匹配表的前一个元素的值。

-若不匹配且i=0,则将当前指针自增1-循环结束后,部分匹配表得到构建。

2.匹配过程:-定义两个指针,i和j,分别指向需要匹配的文本和模式串的开头。

-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。

-若匹配,则将两个指针都自增1-若不匹配且j>0,则将j更新为部分匹配表的前一个元素的值。

-若不匹配且j=0,则将当前指针自增1-若模式串的指针j指向了最后一个字符,则说明匹配成功,返回匹配的位置。

-若循环结束仍未找到匹配的位置,则匹配失败。

总结一下,KMP算法可以分为两个步骤:预处理和匹配。

预处理的过程是构建部分匹配表,通过比较前缀和后缀的最长共有元素的长度,将这个长度记录在部分匹配表中。

匹配的过程是根据部分匹配表中的信息,来确定下一步的匹配位置,提高匹配的效率。

通过KMP算法,我们可以有效地解决字符串匹配问题,提高了匹配的效率。

KMP算法

KMP算法

KMP算法在传统的字符串匹配算法中,最常用的算法是朴素的模式匹配算法。

该算法的基本思想是:从主串的第一个字符开始,逐个字符地与模式串进行比较,如果发现不匹配的字符,则回溯到主串的下一个字符重新开始匹配。

这种算法的时间复杂度是O(m*n),其中m为主串的长度,n为模式串的长度。

在主串与模式串长度相等时,该算法的时间复杂度甚至会达到O(n^2)。

KMP算法的核心思想是利用模式串的信息,避免不必要的比较。

它通过预处理模式串,构建一个部分匹配表(prefix table),来提供匹配失败时的回溯位置。

这样,在匹配的过程中,只需要根据部分匹配表的内容来调整主串和模式串的位置即可。

这种优化使得KMP算法的时间复杂度降低到O(m+n)。

具体来说,KMP算法在预处理模式串时,对于模式串的每个前缀子串,求出其最长的相等的前缀和后缀的长度。

这个长度被称为部分匹配值。

例如,对于模式串"ababc",它的前缀子串有"","a","ab","aba",而其相等的后缀子串有"","c","bc","abc"。

其中,最长的相等的前缀和后缀的长度是2,因此,部分匹配值为2、在KMP算法中,这个信息会被存储在部分匹配表中,即prefix table。

当进行匹配时,如果发现匹配失败,那么根据部分匹配表中的值来进行回溯。

具体来说,如果当前字符匹配失败,那么将模式串向右移动的距离为:当前字符之前的最长相等前缀的长度-1、这样,就可以将模式串与主串对齐继续匹配。

1. 预处理模式串,求出部分匹配表(prefix table)。

2.根据部分匹配表,进行匹配操作。

3.如果匹配成功,返回匹配的位置;否则,返回匹配失败。

总之,KMP算法是一种高效的字符串匹配算法,通过预处理模式串,提供了匹配失败时的快速回溯位置。

KMP算法的应用

KMP算法的应用

01求子串在母串中所有出现的位置给定主串S和模式串T,求T串在S串中所有出现的位置,允许不同位置的T串有部分重叠。

例如:S='abababab',T='abab',T在S中出现的总次数就是3次(包括1、3、5三个起点位置,虽然S[1..4]与S[3..6]有部分重叠,但这是允许的)。

输入信息包括两行,第一行为S串,第二行为T串;按从小到大的顺序输出所有T串出现的位置。

样例:02求多字符串的最长公共子串(POW)给定n个字符串,求这n个字符串的最长公共子串。

例如给3个字符串:'abcb'、'bca'和'acbc',则这三个字符串的最长公共子串即为'bc'。

输入第一行为n,下面n行即为这n个字符串。

输出它们的最长公共子串。

样例:03最长回文子串问题顺序和逆序相同的字符串便是回文串(例如‘aba‘)。

求一个字符串所有的子串中最长的回文串便是最长回文子串问题。

输入内容为一个字符串,输出它的最长回文子串。

样例:04 L-Gap子串问题(gap.pas)如果一个字串形如UVU,U非空,且V恰好有L个字符,我们就称这种UVU形式的字串是一个L-Gap串。

例如,abcbabc是1-Gap 字串,xyxyxyxyxy 既可以是一个2-Gap 字串,也可以是一个6-Gap字串,但它不是一个10-Gap字串(因为U 必须非空)。

现在的问题时,给定一个字串s和一个正整数g, 请你在s串中找出所有的g-Gap子串,并输出所有的g-Gap子串总数。

规定s串仅由小写字母组成,且其长度不超过50,000。

输入:Input第一行为一个数字t(1<=t<=10),表示测试点的个数。

以后的t行,每行有一个数字g(1<=g<=10) 和一个字串s。

输出:对于每一组数据,输出该组数据中所包含的g-Gap 子串的数目。

示例:输入:输出:2 71 bbaabaaaaa 15 abxxxxxab[注]L-Gap Substrings标准算法是二分+扩展KMP 或者后缀树我用的是ZhouYuan教我的O(n^2)加常数优化的方法UvU形式, 枚举长度U的长度L , 设数组B,如果S[i] = S[i + g + L],那么B[i]为1 , 否则B[i]为0。

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

a.计算next数组: next[1]=0。 next[2]=1,next[2]前不存在p1…pk-1=pi-k+1…pi-1 ,因b前只有一个a; next[3]=1,同理,c前只有ab。 next[4]=1,同上道理。 next[5]=2,因为在j位置上a前有p1=p4,即p2-1=p5-2+1 因此,k=2,即next[5]=2。 next[6]=2,道理同next[5]。 next[7]=3,因为在j位置上a前有p1p2=p5p6,即 p1p3-1=p7-3+1p7-1,因此,k=3,即next[7]=3。 next[8]=2,道理同j为5,6。 next[9]=3,道理同j为7。 b.计算nextval数组: nextval[1]=0。 nextval[2]=1,nextval[3]=1,同上。 nextval[4]=0,next[4]=1,因为p4=p1=a,所以,nextval[4]=nextval[1]=0。 nextval[5]=2,因为next[5]=2,但pj≠pk,所以,nextval[5]=next[5]=2。 nextval[6]=1,因为next[6]=2,而p6=p2,所以,nextval[6]=next[2]=1。 nextval[7]=3,因为next[7]=3,但p7≠p3,所以,nextval[7]=next[7]=3。 nextval[8]=1,因为next[8]=2,而p8=p2,所以,nextval[8]=next[2]=1。 nextval[9]=1,因为next[9]=3,而p9=p3,所以,nextval[9]=next[3]=1。
②模式匹配确定模式串在目标串中的位置
序号j: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 目标T:a a b c b a b c a a b c a a b a b c 模式P:a b c a a b a b c j=next[2]=1 a b c a a b a b c j=next[4]=1 a b c a a b a b c j=next[1]=0 a b c a a b a b c j=next[7]=3 a b c a a b a b c 序号j: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 目标T:a a b c b a b c a a b c a a b a b c 模式P:a b c a a b a b c j=nextval[2]=1 a b c a a b a b c j=nextval[4]=0 a b c a a b a b c j=nextval[7]=3 a
一般用next[j]表示与j对应的k值,表明当模式中第j个字符与主 串中第i个字符“失配”时,在模式中需重新和主串中第i字符进行比 较的字符的位置。 s1 s2……………..si-k+1……..si-1 si si+1……sn p1p2……pk-1 pk.pj-k+1 …………pj-1 pj pj+1…..pm 假设此时应与模式串中第k个字符继续比较,则模式中前k-1个字符 的子串必须满足下列关系: “p1p2…pk-1”=“si-k+1si-k+2…si-1” 由部分匹配知: “pj-k+1pj-k+2…pj-1”=“si-k+1si-k+2…si-1” 推得: “p1p2…pk-1”= “pj-k+1pj-k+2…pj-1
0
next[j]=
Max{k|1<k<j且“p1p2…pk-1”= 1
当j=1时 “pj-k+1pj-k+2…pj-1” 其它情况
例: i=3 第一趟匹配 a b a b c a b c a c b a b a b c a c
j=3 next[3]=1 i — i=7
第二趟匹配
a b a b c a b c a c b a b a b c a c
始与Si 继续比较下去。 KMP算法:假设next[j]已经生成。 int index_KMP(strtype p,strtype s,int pos) {int i=pos,j=1; while(j<=m&&i<=n) //m是模式串p的串长,n是主串s的串长 {if(j==0||s.str[i]==p.str[j]); {i++;j++;} else j=next[j]; } if(j>m) return i-m; else return 0; } (2)next[j]数组的性质 从上面的分析可以看出,此种算法的关键在于确定next[j]数组。 若令next[j]=k ,则有: ① 1≤k<j ② substr(P,1,k-1)=substr(P,j-k+1,k-1) 性质②说明,若存在这样的k(next[j]),就应有P的前缀子串k-1 个字符与后缀子串k-1个字符相等。 由性质②可以看出next数组只与模式P本身有关,而与主串S无 关。因此对给定的模式P,我们可以在进行模式匹配之前预先求出next 数组的值。 (3)next[j]数组的生成 由性质可知,next[j]的值就等于这个串p1p2pj-1中相同的前缀子串 和后缀子串的最大长度加1。找前缀和后缀相同的最大真子串,实质上 仍然是一个模式匹配,只是匹配的模式串和目标串是同一个串P。 由定义知: a.next[1]=0 设next[j]=k b.若pk=pj时,则 next[j+1]=next[j]+1 c.若pk≠pj , 则 next[j+1]=next[k]+1 d. 若不存在匹配的子串: next[j+1]=1 j: 1 2 3 4 5 6 7 8
kmp算法课件演示(推荐)
数据结构/数据库 2007-10-12 22:23:51 阅读625 评论1 字号:大中小 订阅
(1)以一个例子引入KMP算法 先看朴素模式匹配过程: (a)S: a b b a b a = = ≠ P: a b a (b)P3≠S3,P右移一位 S: a b b a b a (c) P1≠S2,P右移一位 S: a b b a b a ≠ P: a b a (d) P1≠S3,P右移一位 S: a b b a b a = = = P: a b a (e)匹配成功index(S,P)=4,
substr(S,4,3)=P
从匹配过程看: 首先在(a)中p1=s1,p2=s2,p3≠s3,只需将模式右移到s3,不需将主 串回溯到s2; 其次,由于p1≠p2,可推出p1≠s2,做(b)的比较一定不等; 再由 p1=p3,可以推出p1≠s3,做(c)的比较也一定不等。 因此,由(a)便可直接将P右移三位跳到(d),从p1和t4开始进行比 较,这样的匹配过程对S(主串)而言就消除了回溯。 为要找到一个无回溯的匹配算法,关键在于当匹配过程中,一旦 pj和si比较不等,存在: substr(p,1,j-1)=substr(s,i-j+1,j-1) pj≠si 改进的模式匹配算法的思想: 在匹配过程中,当主串第i个字符与模式串第j个字符“失配”时, 要产生模式串右移的位数和继续与主串(主串无回溯的)比较的字 符,即应该用P中哪个字符和Si进行比较?把这个字符记为Pk,显然有 k<j,并且对不同的j,k值也不相同。这个k 值仅依赖于模式P本身前j 个字符的构成,而与目标S无关。
— j=5 next[5]=2 j=1 i — i=10
第三趟匹配
a b a b c a b c a c b a b a b c a c
j=2
其意义在于: 若next[j]>0表示一旦匹配过程中Pi 与Si 比较不等,可用模式中 next[j]为下标的字符与Si 进行比较; 若next[j]=0表示P中任何字符都不必再与Si 进行比较,而从Si+1开 始。 对于任何模式P,主要的是要确定next[j](j=1,2,3…m)值, next[j] 确定了,就可以加快匹配的过程。 当Pj ≠Si时,P直接右移j-next[j]个字符,或者说P从next[j]开
a a a a 匹配成功
若对于next[j]=k,有pj=pk,当主串中的字符ti和xt[k]进行比较,也就是说,此时, next[j]=next[k]。 序号j: 1 模式: next[j]: nextval[j]: 目标串: a a a 模式串: a j=nextval[4]=0 2 a 0 0 b a 3 a 1 0 a a a 4 5 a a b 2 3 4 0 0 4 a a a b a b a a a b 匹配成功
} else j=nextval[j]; } }
(5)举例 设一模式串为p=’abcaababc’(m=9) 目标串为t=’aabcbabcaabcaababc’(n=18) 要求手工计算next数组和nextval数组;并进行模式匹配,确定模式 串在目标串中位置。 ①手工计算next数组和nextval数组的值为: 序号 j 1 2 3 4 5 6 7 8 9 模式串 a b c a a b a b c next[j] nextval[j] 0 0 1 1 1 1 1 0 2 2 2 1 3 3 2 1 3 1
p: a b a a b c a c k: 0 1 1 2 2 3 1 2 p3=p1 Next[4]=next[3]+1=2 p4≠p2 p4=p1 next[5]=next[2]+1=1+1=2 P5=p2 Next[6]=next[5]+1=3 p6 ≠p3 p6 ≠p1 next[7]=1 p7=p1 next[8]=next[7]+1=2 next函数的算法:求next数组 void next(strtype t) {int next[m],j=1,k=0; next[1]=0; while(j<t.len) {if(k=0||t.str[j]==t.str[k]) {j++;k++;next[j]=k;} else k=next[k]; //向前递推找最大匹配的k,模式串右移 } } 方法归纳如下: a.考察模式串,令next[1]=0; b.对于从第2个字符开始的next[j],分析在j位置前的j-1个字符串中 是否存在一个k,使得在k前的k-1个子串等于j前的k-1个子串(即j前 的j-1个字符存在前后缀子串匹配); 若不存在,则next[j]=1; 存在,则next[j]=k。 注意:k 应使匹配子串最大。 例:已知模式串p=‘abcaabbabcab’,写出用KMP法求得的 每个字符对应的next和nextval函数值。 序号j: 1 2 3 4 5 6 7 8 9 10 11 12 模式p: a b c a a b b a b c a b next[j]: 0 1 1 1 2 2 3 1 2 3 4 5 nextval[j]:0 1 1 0 2 1 1 0 (4)next函数修正值算法 分析模式“aaaab”的next[j]。 1 1 0 5
相关文档
最新文档