Knuth-Morris-Pratt算法:

转载来自http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html的博文(可以说是非常简洁明了清晰易懂了):

分割线                                                                                            begin

1.

首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。

2.

因为B与A不匹配,搜索词再往后移。

3.

就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。

4.

接着比较字符串和搜索词的下一个字符,还是相同。

5.

直到字符串有一个字符,与搜索词对应的字符不相同为止。

6.

这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。

7.

一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

8.

怎么做到这一点呢?可以针对搜索词,算出一张《部分匹配表》(Partial Match Table)。这张表是如何产生的,后面再介绍,这里只要会用就可以了。

9.

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照下面的公式算出向后移动的位数:

  移动位数 = 已匹配的字符数 - 对应的部分匹配值

因为 6 - 2 等于4,所以将搜索词向后移动4位。

10.

因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。

11.

因为空格与A不匹配,继续后移一位。

12.

逐位比较,直到发现C与D不匹配。于是,移动位数 = 6 - 2,继续将搜索词向后移动4位。

13.

逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果还要继续搜索(即找出全部匹配),移动位数 = 7 - 0,再将搜索词向后移动7位,这里就不再重复了。

14.

下面介绍《部分匹配表》是如何产生的。

首先,要了解两个概念:"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

15.

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

  - "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

16.

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

分割线                                                                                            end

在模板中,我们把“部分匹配值”定义为Next数组,那么怎么求Next数组?看模板:

void getnext(const char pat[],int Next[])
{
int i=, j=-, len=strlen(pat);
Next[]=-;
while(i<len)
{
if(j == - || pat[i] == pat[j]) Next[++i]=++j;
else j=Next[j];
//printf("now i=%d j=%d next[%d]=%d pat[%d]=%c\n",i,j,i,Next[i],i,pat[i]);
}
}

如果不太懂这个算法过程怎么一步步求得一个模式串的Next数组的,可以尝试手工模拟运行一下下面两个字符串:

pat①:"ababcababab";

pat②:"ababcababdb";

至于如何进行匹配,根据上面的讲解,很简单:

int kmp()
{
int i=, j=, len1=strlen(str), len2=strlen(pat);
while(i<len1)
{
if(j == - || str[i] == pat[j]) i++, j++;
else j=Next[j];
}
}

进行遍历即可。

KMP算法小记的更多相关文章

  1. 扩展KMP算法小记

    参考来自<拓展kmp算法总结>:http://blog.csdn.net/dyx404514/article/details/41831947 扩展KMP解决的问题: 定义母串S和子串T, ...

  2. 【2018.07.27】(字符串/找相同)学习KMP算法小记

    虽然说原理很好理解,但是代码理解了花费我一个下午的时间,脑阔痛 该注释的地方都标记了,希望以后看到这些代码我还能好好理解吧 学习的链接地址:https://www.cnblogs.com/teble/ ...

  3. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  4. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

  5. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  6. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  7. 数据结构与算法JavaScript (五) 串(经典KMP算法)

    KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配 ...

  8. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  9. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

随机推荐

  1. HTTPS原理,以及加密、解密的原理。

    https://blog.csdn.net/Yang_yangyang/article/details/79702583 摘要:本文用图文的形式一步步还原HTTPS的设计过程,进而深入了解原理. A在 ...

  2. IIS------项目配置到IIS后报500错误

    转载: http://blog.csdn.net/yinjingjing198808/article/details/7185453 错误一: HTTP Error 500.19 - Internal ...

  3. Mybatis -- 批量更新 -- updateBatch

    mysql数据库配置: 数据库连接必须配置:&allowMultiQueries=true并且‘&’ 用&替换 jdbc.url=jdbc:mysql://192.168.10 ...

  4. Lua协程-测试3

    print("Lua 协程测试3") -- 实现消费者-生产者关系(生产一个就消费一个) count = -- 生产总数 -- 生产者 local newProductorCo = ...

  5. 【RF库Collections测试】Set List Value

    Name:Set List ValueSource:Collections <test library>Arguments:[ list_ | index | value ]Sets th ...

  6. Qt打包部署程序自动查找依赖DLL工具windeployqt

    qt编译好一个exe程序之后,部署到一台没有开发环境的机器上,需要一起拷贝其依赖的dll文件.这时需要一个windeployqt工具来帮忙,因为手动拷贝的话容易遗漏. https://blog.csd ...

  7. Unity透明Shader

    Shader "Custom/Blocks" { Properties { _Color (,,,) _MainTex ("Albedo (RGB)", 2D) ...

  8. O2O(online to offline)营销模式

    O2O营销模式又称离线商务模式,是指线上营销线上购买带动线下经营和线下消费.O2O通过打折.提供信息.服务预订等方式,把线下商店的消息推送给互联网用户,从而将他们转换为自己的线下客户,这就特别适合必须 ...

  9. oracle 排序字段自增长

    <insert id="insertGoodsDescription" parameterClass="goodsDescription" > &l ...

  10. 探求C#.Net中ArrayList与Array的区别

     ArrayList与Array的区别概述     ArrayList 是数组的复杂版本.ArrayList 类提供在大多数 Collections 类中提供但不在 Array 类中提供的一些功能.例 ...