首页 > 编程知识 正文

kmp算法和bf算法 区别,数据结构kmp算法详解

时间:2023-05-05 02:35:46 阅读:140052 作者:2833

3358www.Sina.com/(string )是一个由至少零个字符组成的有限序列。 如下图所示

一. BF算法

二. KMP算法

一.前缀、后缀、最大公共前缀

二、研究KMP和BF的差异(主要是回溯) )。

三. next序列描述

j位置的确定(即next数组的详细解) ) ) ) ) ) ) ) )。

如果n=0,则为空白字符串,与空白字符串不同。

由字符串中任意连续字符组成的子列(包括空字符串)即为字符串的子列。 子串的概念与数学中的集合相似,如下图所示有cxdsb串

目录

虽然省略了具体的初始化、创建等,但在实际开发中无法隐含地遵守规则。 重要的是学习两种算法

http://www.Sina.com/http://www.Sina.com /

ffdst开始S[0]!=T[0],因为也同样满足条件,所以S[s]!=T[t],回溯成立。 循环这个步骤的条件是s,t都比串长小

图来自于bilibili王卓老师

代码按以下方式实现: 以字符数组为例主要给出了算法)

char S[7]={'abcacbb'}; char T[4]={'cacb'}; int s=0; int t=0; while(ssizeof(s ) t sizeof(T ) t ) )/j的范围在主字符串中,t的范围在子字符串中if(s(s )=t (t ) ) ) s; t; //如果值相等,则下一个元素(else ) s=s-t1; //回溯子字符串主字符串t=0; ) if(t )=='/0 ' ) ) {return 1; //找到了}else {return 0; ///循环还没完成}} 一、BF算法KMP算法主要在回溯方面进行了优化,避免了傻瓜式回溯跑到顶。 重要的是找到最大前缀以减少浪费的过程。

由于网上的讲解很多,所以我这一部分主要分为3358www.Sina.com/和此算法也称为简单匹配算法。实际上即是暴力穷举法,算法时间复杂度为O(n*m),为方便理解算法先看下面图解两部分进行说明。 我的这一部分总结为以下步骤。

当前面元素都满足条件S[s]==T[t],且进行到T[t]=="/0"时,代表匹配到了字符。此算法每次都要回溯因此时间复杂度为0(n*m)

前缀、后缀、最大公共前缀的概念

研究KMP和BF的差异(主要是回溯) )。

next序列的说明

二、KMP算法前缀的概念照原样看以下例子,比看例子理解要快。 在这里不需要考虑原理什么的。 需要使用这三个概念。 作为平时的知识,

这些字符串包括

  “abcde” 
前缀的集合:{a,ab,abc,abcd}
后缀的集合:{e,de,cde,bcde}
公共缀:就是该字符串 前缀后缀都包含的元素如下图所示
最大公共前后缀:如图中所示字符串“a b c a b d a”有 公共的前后缀为 a,b,ab三种情况,但最大的公共前后缀 就为ab.
失配位:即不相等时的位置。

 那么最大公共前后缀有什么意义呢?接下来就进入正题。(本段思路来自天勤考研)

我们设定主串为 S[11]={"abcabbbabc"},子串为 T[5]={"abcabc"},i,j分别为数组下标

 如下图所示,S[i] T[j] 分别对应,直到 i=j=5时,即第六个元素时,二者不相等
当遇到不相等的情况是,BF的算法是将i回溯到 i-j+1 的位置,即之前比较的后一个位置
然而对于Kmp算法则不同,Kmp首先找到主串子串相同的部分的最大公共前后缀,
其次将子串的前缀挪到与主串后缀的地方对齐。再进行S[i] T[j] 的比较。

总结:步骤为  ①找到 失配位 ② 找到最大公共前后缀     

二、研究KMP与BF的区别 (主要是回溯)

那么为什么可以直接跳过这些元素而直接比较呢,即为什么 i 可以不回溯,j回溯位置也不用从头开始呢。那么接下来就进行此步骤的剖析:

 当遇到不相等元素时证明主串子串在此元素之前一定都相等。那么先看相等这一部分,如图所示,若子串向移动,不管移动多少次,子串头元素a只有遇到后缀a时才会相等。那么同理b也是,因此我们直接找到最大公共前后缀,进行对齐即可。这里的移动只是方便看图,实际上移动的 只有 j  。这里的最大公共前后缀是在失配位之前寻找,(即绿线之前)
由此步骤我们得出代码如下所示

 

图片来自bilibili kddmz老师 

BF算法在本文上面有提到,那么Kmp算法与其不同的地方主要在于判定条件,与回溯两处。此处判定条件 j=-1 会越界因此要加上条件,具体在后面会有讲到。j=next[j] 是 j 的回溯条件,即如何确定 S[i] T[j] 不相等时,j 的回溯位置 !!!再此强调 i 是不用回溯的,敌动我不动即可。只有在匹配成功后才会和 j 一同跳到下一个位置。

三、next数组的讲解

那么以上所有步骤,就是Kmp算法的整体架构,接下来我们只需要考虑 next 数组了,同时这里也是最关键的地方 !!!

next数组的意义在于找到每次  S[i] T[j] 不相等时,即失配位时,j 的回溯位置 , 这里我们先以手算法,讲解以便于理解后面的代码部分

事实上,在我们“移动”的过程中,根本不需要看主串,只需要看 子串(模式串)即可,直接将字串的最大前缀移动到最大后缀出即可如下图所示。此时我们再此强调,所谓的移动指示假想的,实际上是 j 的移动,如图 j 从原来失配位移动到了后缀之后。

j 位置的确定 (即next数组的详解)

一、手算图解法

此法仅仅为了方便观察对应代码来思考方便理解。(这里我们用的一组子串来演示)

由上图可知,想要判断最大公共前后缀只需要子串即可,那么我们制作以下表格

这里的 T 代表了子串(模式串)后面数值为 子串内容,下标为串数组对应下标,next即为 j 要回溯的位置。
注意:这里next不同视频教程,有不同的版本,大概讲解一下,其实就是各个位右移的区别。
本文采用第二种方式 (这里不懂下面讲)

next数组的求法

  

第一步:数组初始化:

我们设定  j 为前缀 i 为后缀 。数组初始化 j 就等于0,对应的数组元素就等于 a,i为后缀所以 i=3,此时的 j 对应的 next值即为 -1.这里可以是0,也可以是-1,对应的上面的表,那么数组外部的 j=next [] =-1; 此时就对应之前的判断条件,为什么要加上j=-1。

第二步:求next [ j ]的值 

求法是前n项 是否有公共前后缀,没有填0,有一个则填1,有两个填2,以此类推 
当 j =-0时,数组初始化,  next [1] = -1;
 当 j =1 时,前面就只有a一个元素,所以   next [1] 应该为 0;
 当 j =2 时,前面有a b  两个元素,  所以    next [2] 应该为 0;
 当 j =3 时,前面有a b a 三个元素,所以    next [3] 应该为 1;(有公共前后缀 a)
后面以此类推,结果如下表

 二、代码解法

将图表和代码结合看

 总结:j 始终指向 a的位置,移动的为 i ,当遇到 j==-1 或 T [ i]=T [ j ]时才会+1,进行下一元素比较,如果相等其实是代表了最大公共前后缀有2位,若不相等,则证明只有一位最大公共前后缀,与此同时,j=next[ j ],也就是回退到值等于a的地方。 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。