KMP算法(主要解释next表的构造)

零、先说点题外的吧

  这一章学串,其中最经典的就是模式匹配的KMP算法。其实也算是巩固自己的知识,我把这一章的知识和zy顺了一遍,主要讲了KMP算法。大概讲了一个小时,讲完了之后,zy很兴奋的说了一句:感觉好神奇啊。很感动。感觉终于让一个没有领略过算法魅力的人感受到了算法的魅力,感觉她能从简单几行代码里“发现人类智慧居然如此璀璨”。

  很遗憾。

  我等你终有一天可以东山再起王者归来。

一、KMP思路

  1.想要理解KMP,就要先理解最朴素的暴力算法

    //此处省略N个字……不懂看书吧

  2.KMP相当于对它的优化

    暴力算法的复杂度是O(nm),即最坏情况下对每一个位置的主串数据遍历一遍模式串。其缺点在于,对主串数据重复遍历了很多遍,对模式串更是遍历了无数遍,尽管早就知道其中的数据了。

    KMP的优化在于对其元素进行一次遍历,并把所需要的数据记录下来,避免以后重复遍历。

    KMP算法的特点即:快速后移+决不后退(主串)!

二、主代码实现

  //略……

  注意了,在对这段主代码时,next表先不用理解,只要先讲其视作已知,将其每个位置理解为该后退到哪个位置即可。

三、next[]表的构造(关键)

  1.next[j] 存的是该后退到的位置,即:模式串[0..j-1]中(或者说[0,j)中),匹配的模式串前缀和和主串后缀的最大长度。即模式串[0..j-1]与模式串[i-j,i-1]能匹配。

    注意是模式串0..j-1而不是0..j!!!!!!!!!!!!!!!!!!!!!

  2.当模式串前缀和后缀没有匹配,则next[j]=0,即长度为0,重新开始匹配。

  3.next[0]=-1;

    j指向的是 主串[i-j,i)与模式串[开头,j)匹配,所以next[0]=-1相当于在-1处引入一个不存在的哨兵,简化代码统一理解。将特殊情况转化为普通情况进行处理。同样可以将其视为一种标记,即第一个元素都不匹配时,标记j<0,然后重新处理。

  4.next[]表的构造。即对模式串的每一个位置之前的子串进行自匹配。

  分析:

    看到网上有用数学归纳法来解释求解步骤。(数学归纳法有三个步骤,①初始条件成立②假设n=k情况成立③从n=k情况推导n=k+1的情况,若n=k+1的情况成立,则公式对自然数集成立。)其实感觉并不完全准确。这里用递推来说更准确一些。递推说的是,已知初始情况,则以后的任意n+1的情况均可以由n的情况推出。

    只是应用到这个问题上求解步骤略微有些不同,递推的初始条件其实是很难界定的,我们不妨事后再进行考虑,我们可以先假设f(n)已知,然后考虑如何从n的情况推导出n+1的情况。

  步骤:

    (模式串此时视为主串P,指针为j;模式串的模式串此时称为次模式串C,指针为t)。

    假设next[j]已知,注意是0..j-1 的最长前后缀已知,不是0..j    

      1)若P[j]==C[t] /* C[next[j]] */ 则并进且更新next表 t++;j++;next[j]=t;//区别,更新表

      2)若P[j]!=C[t] 则次模式串指针后退且不更新next表(直至相等或者到头时进行更新)//非区别,后退不更新

      3)重复上述步骤1)2)至next表更新至最后一个数据。

  问题:

    上述步骤留了一个问题,那就是初始条件。步骤2)中也存在一个简单问题,就是到底该退到什么时候?其实这是一个问题,那就是如何设置初始条件。

    首先明确,当当前的序列无匹配的前后缀时,则应将next表在该位置设置为零。那么如何确定无匹配后缀呢?其实这还是如何设置初始条件的问题。说的再明确一点,那就是next[0]改如何设置的问题。那么该如何设置呢?其实这个问题在KMP主程序中说明过一遍。

    因为next[j] 存的是模式串[0..j-1]中(或者说[0,j)中),匹配的模式串前缀和和主串后缀的最大长度。[0,-1]显然不好讨论,当然其实next[0]表示的其实也不是“存的是模式串[0..j-1]中(或者说[0,j)中),匹配的模式串前缀和和主串后缀的最大长度”next[0]表示的是当退到0的位置该如何处理,不妨先说一下next[1],按照上面的说法,next[1]应该表示将模式串[0..0](即模式串首元素)视作主串,此时的最大前缀,有人说这还用说嘛,肯定是1啊,如果真这么设定,那么我们假设一下,当P的某个字符和C[1]不相等时,指针t将退回next[t]即next[1],这样就相当于无变化,那该如何设置next[1]呢,想想此时该如何处理?其实是应该将j++,然后重新对j++之后的j与C[0]比较,为了使得这种特殊情况和普通情况应用步骤1)统一处理我们只需把指针t(此时t指向0)退一步,然后在j、t并进在比较即可,此时将t退一步,即假设有个t-1的哨兵,将t退到-1即可,用代码表示即为next[0]=-1。这样来看,next[0]虽然并不表示最长前后缀长度,但是还是表示“后退的位置”从这个语义上来说,其实next[0]与next表的其它值也保持了吻合。至于next[2]呢,next[2]可以通过next[1]用上述步骤推出啊……【笑哭】

好了,这样问题基本上就全部解决了。这样看来,KMP算法最重要的就是next表的实现啊。

    

    

    

   

时间: 2024-10-23 11:40:42

KMP算法(主要解释next表的构造)的相关文章

KMP算法具体解释(贴链接)

------------------------------------------------------------------------------------------------------------------------------------------------------ 欢迎光临天资小屋:http://user.qzone.qq.com/593830943/main --------------------------------------------------

KMP 算法简单解释

KMP 算法简单解释 ? 讲KMP算法,离不开BF,实际上,KMP就是BF升级版,主要流程和BF一样,就是在削除回溯上花了点功夫,利用Next数组来削除 <( ̄︶ ̄)[GO!] 1. 先看看BF算法(暴力破解) int Brute_force_1(const char *S, const char *T) { if (!S || !T) return -1; int lenS = strlen(S); int lenT = strlen(T); int i = 0; //主串下标索引 int j

KMP算法具体解释(转)

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

小谈KMP算法

刚接触KMP算法时,真是一头雾水,主要就是关于next跳转表是如何算出的,看了很久才勉强看明白,下面就是一点个人见解. 1.首先我要推荐先看这篇文章:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 看完这篇文章之后能明白kmp的主要思路是什么了 字符串匹配的KMP算法 作者: 阮一峰 日期: 2013年5月 1日 字符串匹配是计算机的基本任务之一. 举例来说,有一个字

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

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

字符串匹配KMP算法C++代码实现

看到了一篇关于<字符串匹配的KMP算法>(见下文)的介绍,地址:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html,这篇博客对KMP算法的解释很清晰,但缺点是没有代码的实现.所以本人根据这位大神的思路写了一下算法的C++实现. C++代码如下: #include <iostream> #include<string.h> using namesp

KMP算法深度解析

[原文参考] http://www.ics.uci.edu/~eppstein/161/960227.html 摘要:KMP算法是字符串匹配的经典算法,由于其O(m+n)的时间复杂度,至今仍被广泛应用.大道至简,KMP算法非常简洁,然而,其内部却蕴含着玄妙的理论,以至许多人知其然而不知其所以然.本文旨在解开KMP算法的内部玄妙所在,希望能够有助于学习与理解. 1.KMP算法    一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此称之为KMP算

字符串匹配(KMP 算法 含代码)

主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知识 串(string或字符串)是由零个或多个字符组成的有限序列,一般记为 当中s是串的名,用单引號括起来的字符序列是串的值:ai(1<=i<=n)能够是字母.数值或其它字符.串中字符的数组 n称为串的长度.零个字符的串称为空串,它的长度为0 串中随意个连续的字符组成的子序列称为该串的子串. 包括子

KMP算法【转】

转自http://blog.csdn.net/joylnwang/article/details/6778316/ KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法.但是相较于其他模式匹配算法,该算法晦涩难懂,第一次接触该算法的读者往往会看得一头雾水,主要原因是KMP算法在构造跳转表next过程中进行了多个层面的优化和抽象,使得KMP算法进行模式匹配的原理显得不那么直