KMP串匹配算法解析与优化
朴素串匹配算法说明
串匹配算法最常用的情形是从一篇文档中查找指定文本。需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧。
为了更好理解KMP算法,我们先这样看待一下朴素匹配算法吧。朴素串匹配算法是这样的,当模式串的某一位置失配时将失配位置的上一位置与查找串的该位置对齐再从头开始比较模式串的每一个位置。如下图所示。
KMP串匹配算法解析
KMP串匹配算法是Knuth-Morris-Pratt算法的简称,KMP算法的思想就是当模式串的某一位置失配时,能不能将更前面的位置与查找串的该位置对齐,并且直接从该位置开始比较。按照这个思路走,问题叫变成了:当模式串的某一位置失配时要找到一个更前面的位置与查找串的该位置对齐。模式串的某个位置失配时的这个更前面的位置就叫做回溯位,通常用next表示,它的计算公式是:
next[i]= { 0; 当 i = 1
k; 对于串P,存在1 <= k < 使得 P1..Pk-1 == Pi-k+1..Pi-1
1; 其他情况 }
这个公式对应的串的下标是从1开始的。这个公式只说明:模式串中某一位置(不包含此位置)之前部分具有首尾相同的子串(即自匹配,比如ABCABA最后一个A之前头部和尾部都包含了子串AB)时,如果该位置失配可以直接将头部子串的下一个位置和该处对齐(比如模式串ABCABA在最后一个A处失配可以直接滑动模式串将C对齐原来最后那个A对齐的位置),这样可以去掉模式串在某位置失配时该位置之前的子串在朴素匹配算法中存在的冗余比较(如果用朴素匹配算法,需要将模式串ABCABA移动三次才能使得C对齐原来最后那个A对齐的位置)。模式串中某一位置(不包含此位置)之前部分不具有首尾相同的子串时,在该位置失配时可以直接让模式串的开始位置对齐该位置。如下图。
这里只给出了算法的说明,但是如何能够证明算法是正确的呢?这个说麻烦也麻烦,说简单也简单。为什么麻烦呢?因为我没办法用形式化的语言给出证明过程,就像数学里面的证明过程一样。其实自己通过形象思维演示一下串匹配的滑动过程就能够相信这个算法肯定是正确的。我也懒得给出证明过程。
接下来给出KMP算法的完整代码。
#include <iostream> #include <iomanip> #include <vector> #include <string> #include <cstdlib> using namespace std; void get_next(const string & M,vector<int> & next); int KMP_match(const string & S,const string & M,int pos); int main( ) { string S="abcdefghabcdefghhiijiklmabc"; string T="hhiij"; ); cout<<"\n"<<pos<<endl; system("pause"); ; } void get_next(const string & M,vector<int> & next) { //按模式串生成vector<int> next(M.size(),-1); //这里的串的第1个元素下标是0 , j = ; ; do { ) || (M[i] == M[j])) { i++; j++; next[j] = i; } else i = next[i]; cout<<)<<i <<)<<j <<)<<next[j]<<endl; }while( j < M_len); } int KMP_match(const string & S,const string & M,int pos) { ;//这里的串的第1个元素下标是0 int S_len = S.size(); int M_len = M.size(); if((S_len-pos) < M_len) ; vector<); get_next(M,next); while (i<M_len && j<S_len) { || S[j]==M[i]) { ++i; ++j; } else i = next[i];//j不变,i跳动 } if (i == M_len) return j-i;//匹配成功 ; }
KMP串匹配算法的优化
接着看上面EBAEB的匹配例子。其中第2次比较根本没有必要,可以直接跳到第3次。这次比较有一个特点:当模式串滑过一段距离后模式串中参与比较的字符和前次参与比较的字符相同,都是B。按照上面那个公式求上述模式串回溯位置时的一个情形如下:
此时确定的是模式串中索引为4的元素失配时模式串的回溯位置,这时索引位下一个元素和比较位的下一个元素相同(都为B)。同时这也是模式串中索引为4的字符失配后滑动完成的情形,即最后一个B和查找串种的D不匹配时,由于next[4] = 1,需要把索引为1的字符(就是第2个字符)B对其到D。但是这个B和D是不是已经比较过一次了啊。这是因为不仅模式串失配位置之前的部分能够自匹配,而且模式串中包含失配位置的之前部分也能自匹配。模式串中包含失配位置的之前部分组成的子串也具有相同的首尾时,失配位置的回溯位置可以直接采用首部字串的回溯位置,对于串EBAEB,可以让next[4]直接等于next[1]。那么优化的next函数如下:
next[i]= { ; 当i = k; 对于串P,存在1 <= k < 使得 P1..Pk- == Pi-k+..Pi- & Pk != Pi next[k]; 对于串P,存在 <= k < i使得 P1..Pk == Pi-k..Pi ; 其他情况 }
接下来给出改进后的就next数组的代码。
void get_next(const string & M,vector<int> & next) { //按模式串生成vector<int> next(M.size(),-1); //这里的串的第1个元素下标是0 , j = ; ; do { ) || (M[i] == M[j])) { i++; j++; if(M[i] != M[j]) next[j] = i; else next[j] = next[i]; } else i = next[i]; }while( j < M_inx); }
KMP串匹配算法解析与优化的更多相关文章
- KMP算法解析(转自图灵社区)
KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...
- 串匹配算法讲解 -----BF、KMP算法
参考文章: http://www.matrix67.com/blog/archives/115 KMP算法详解 http://blog.csdn.net/yaochunnian/artic ...
- BM串匹配算法
串匹配算法最常用的情形是从一篇文档中查找指定文本.需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧. BM算法好后缀规则 公式: 对于长度为m的模式串P,在i处失配时,模式串向前滑动的 ...
- KMP(Knuth-Morris-Pratt)算法
一.朴素匹配算法 也就是暴力匹配算法.设匹配字符串的长度为n,模式串的长度为m,在最坏情况下,朴字符串匹配算法执行时间为O((n - m + 1)m). 假设m = n / 2, 那么该算法的复杂度就 ...
- 地理围栏算法解析(Geo-fencing)
地理围栏算法解析 http://www.cnblogs.com/LBSer/p/4471742.html 地理围栏(Geo-fencing)是LBS的一种应用,就是用一个虚拟的栅栏围出一个虚拟地理边界 ...
- python常见排序算法解析
python——常见排序算法解析 算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法 ...
- GBDT+LR算法解析及Python实现
1. GBDT + LR 是什么 本质上GBDT+LR是一种具有stacking思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于Facebook 2014年的论文 Practical L ...
- 区块链~Merkle Tree(默克尔树)算法解析~转载
转载~Merkle Tree(默克尔树)算法解析 /*最近在看Ethereum,其中一个重要的概念是Merkle Tree,以前从来没有听说过,所以查了些资料,学习了Merkle Tree的知识,因为 ...
- 程序员收藏必看系列:深度解析MySQL优化(二)
程序员收藏必看系列:深度解析MySQL优化(一) 性能优化建议 下面会从3个不同方面给出一些优化建议.但请等等,还有一句忠告要先送给你:不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而 ...
随机推荐
- 有没有一行文件字过多后可以省略号显示,我说的不是用其他样式,BT本身有没有?谢谢
.text-overflow {display: inline-block;max-width: 200px;overflow: hidden;text-overflow: ellipsis;whit ...
- 一些代码 I (斐波那契、for...else...、try和return、classmethod、统计个数)
1. 斐波那契 from itertools import islice def fib(): a, b = 0, 1 while True: yield a a, b = b, a+b print ...
- 关于 Python Iterator 协议的一点思考
转:http://www.jianshu.com/p/dcf83643deeb Python 中有好几种容器或者序列类型:list tuple dict set str,对于这些类型中的内容,往往需要 ...
- Python 的 List 要印出 中文 編碼
Python 的 List 如果有中文的話, 會印出 \xe4\xb8… 等等的編碼, 要如何印出中文呢(如下範例)? (Debug 方便查看) View Raw Code? >>> ...
- FreeMarker语法知识
FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:1,文本:直接输出的部分2,注释:<#-- ... -->格式部分,不会输出3 ...
- 【转】sed命令详解
原文:http://www.cnblogs.com/emanlee/archive/2013/09/07/3307642.html sed命令行格式为: sed [-nefri] 'command' ...
- spark1.2.0版本SparkSQL使用parquet类型注意事项
在Spark1.2.0版本中是用parquet存储类型时注意事项: sql语句: select * from order_created_dynamic_partition_parquet; 在spa ...
- 内省—beanutils工具包
Apache组织开发了一套用于操作JavaBean的API,这套API考虑到了很多实际开发中的应用场景,因此在实际开发中很多程序员使用这套API操作JavaBean,以简化程序代码的编写. BeanU ...
- 日期:Date
API--- java.util.Date:日期类,月份从0-11: 日期对象和毫秒值之间的转换. 1,日期对象转成毫秒值.Date类中的getTime方法. 2,如何将获取到的毫秒值转成具体的日期呢 ...
- HTML5自定义属性对象dataset
前面转载的"图片懒加载",因为基础不好,里面判断dataset的语句看不懂,经别人推荐找到一篇专门讲解dataset的文章,我心甚悦^ http://www.zhangxinxu. ...