KMP算法详解
来源:互联网 发布:linux . 编辑:程序博客网 时间:2024/06/06 18:36
KMP算法简介
本文主要对KMP的实现方式进行简单的介绍,主要内容如下所示:
- 什么是KMP
- KMP的实现思路
- 算法的代码实现方式
- 代码完善
什么是KMP
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法) —— [ 百度百科 ]
之前上学做JavaWeb开发的时候,为了偷懒从网上第一次看到了KMP算法,当时花了好长时间才搞懂。KMP有一个很有趣的名字“看毛片”算法,主要用来高效率的进行字段匹配。虽然算法提出时间比较早而且网上资料众多,但是由于算法本身比较晦涩 所以鲜有博主能简洁明了的将其讲清楚,本文主要集中讲解KMP跳表部分。
KMP的实现思路
上文说到KMP的主要作用就是字段匹配,即给定两个String类型的参数O和f,长度分别为n和m(m<=n)判断B是否出现在O中,如果出现了就返回出现位置的index。
常见的思路是从O的第一个字节开始依次遍历和f进行比较,如果发现相同的就返回index,但是这种方法的复杂度为O(nm),KMP通过一个复杂度为O(m)的跳表将复杂度降低到了O(n+m)。
假设我们在O中找f,两个String的1到i-1位是想等的,第i位不相等,通常的做法是将f前移1位,但是kmp的做法是将f前移多位,而具体移动多少位 就是通过跳表计算出来的。
假设我们知道前移K(k<=i)位,反向分析 我们可以得出结论:
-A是黑色部分的头部
-B是黑色部分的尾部
-A和B是相等的两个String
通过上面的讲解我们可以发现KMP的跳表就是一个计算图中A和B最大长度的工具,当然这里的长度不可以是f本身,因为这样的话最大长度就只能是f自己了,下面我们来看看跳表的具体生成方式。我们的例子是从BBC ABCDAB ABCDABCDABDE中寻找ABCDABD
1.第一步是把B和A进行比较,因为不一样 所以后移一位
2.然后B和A进行比较,因为不一样 所以后移一位
3.因为A和A一样,即字符串中出现了和分词索引一样的字节,所以本次不移动
4.然后比较下一个,A===A 还是不移动
5.直到D和O中的空格不一样了,我们停下来
6.现在很多同学的反应时f向后移动一位,再次进行比较,这样做虽然可以 但是性能不高因为第A-D之前的位置我们是比较过的,没必要再重复比较一次
7.我们观察得到,空格和D不匹配的时候前6个字符是相同的,所以我们就利用这个线索跳过已经比较过的位置,将f向后移动多位以提高效率
8.我们先给出一张跳表,至于这个是如何产生的 详见文章末尾
9.我们现在有了跳表,知道前6个字符是相同的,KMP给出了如下计算公式:下次后移位数=已经匹配的字符数-跳表中对应的数字,我们这里对应的就是6-2=4,所以我们可以后移4位。
10.因为C和空格不一样,这是前面相同的字符是2,对应跳表的值是0,所以2-0=2,后移2位
11.因为A好空格不匹配,后移一位
12.后面进行多次比较,我们发现C和D不一样,意识6-2=4,我们后移4位
13.按照前面你的规则进行比较,知道f的最后一位完全匹配,7-0=7,我们移动7位,到目前为止我们在A中发现了第一个完全匹配的f
下面我们介绍跳表的生成,在这之前我们来介绍两个概念,前缀还有后缀,“缀”的含义就是除了字符串本身以外的所有连续的字符串组合,前缀就是从前开始 后缀就是从后开始。下面我们以一个例子来作为讲解。
-字符串 abcd
-前缀 a,ab,adc
-后缀 d,cd,bcd
有了这两个概念,我们来介绍跳表是如何产生的。以例子中的ABCDABD为例。
所以就有个如下表格
仔细观察上表,我有个大胆的猜想,跳表的作用就是当字符串的首部和尾部有重复的时候,比如ABCDAB中,我们可以直接将首部AB移动到尾部AB的位置,加快比较的速度。
算法的代码实现方式
通过上面的讲解,我们大致了解了KMP的实现原理,这里我们回归主题看看如何用代码来实现这个算法,首先我们看看跳表的实现。
makeNext = (const char P[],int next[]) => { let q,k; //q:模版字符串下标;k:最大前后缀长度 let m = strlen(P); //模版字符串长度 next[0] = 0; //模版字符串的第一个字符的最大前后缀长度为0 for (q = 1,k = 0; q < m; ++q) //for循环,从第二个字符开始,依次计算每一个字符对应的next值 { while(k > 0 && P[q] != P[k]) //递归出最大的相同的前后缀长度k k = next[k-1]; if (P[q] == P[k]) //如果相等,那么最大相同前后缀长度加1 { k++; } next[q] = k; }}
代码完善
待续 还在构思中…
- KMP算法详解 【KMP】
- KMP算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解 转帖
- KMP算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解 转帖
- KMP匹配算法详解
- KMP算法详解
- KMP算法详解
- KMP算法详解
- 转:KMP算法详解
- KMP算法详解(转)
- [BZOJ]4347: [POI2016]Nim z utrudnieniem DP+SG函数
- logstash通过kafka传输nginx日志
- C#编程常用23种模式
- 图的基本概念
- 718. Maximum Length of Repeated Subarray
- KMP算法详解
- [USACO09OPEN]滑雪课Ski Lessons
- CT重建学习笔记(一)
- 期望dp小结
- oracle创建表空间,用户及授权
- 云片短信验证
- 生活小记37
- Oracle数据库中插入日期,日期带有时分秒(java.util.Date类型)
- 20171031分包班组宝动作