[数据结构]模式匹配算法--KMP算法详解
目录
- 一. 模式匹配
- 二. 模式匹配算法
- 1. 朴素模式匹配算法
- 2. KMP算法
- 1). KMP算法的优势
- 2). KMP算法的原理
- 3). next数组的构造
- 4). 利用next数组匹配的过程
- 二. KMP算法的代码实现
- 1. 生成next[]数组
- 2. KMP查找过程代码
一. 模式匹配
当有两个字符串Str = "abdabcde;
和 modStr = "abcd";
时,如果要在Str中查找与modelStr相等的子串,则称Str为主串,modelStr为模式串。在查找过程中,从Str中的第一个字符进行比较,如果找到与modelStr相同的子串,函数返回modelStr字符串第一次出现的位置,否则返回-1。以上过程就称为模式匹配.
二. 模式匹配算法
模式匹配算法,最广为人知的有两种算法,一种为简单且暴力的BF算法,一种为效率极高的KMP算法。下文将会对两种方法进行详解。
1. 朴素模式匹配算法
BF算法为朴素模式匹配算法的经典,该算法的主要思想,从主串的第一个字符与模式串中的第一个字符进行比较,若相等则继续比较,若不相等则从主串中不相等的位置与模式串中的第一个字符进行比较。
指针i
指向主串,j
指向模式串,当匹配失败时,i
移动的位置为i = i - j + 1
。
当所有字符串匹配成功后,指针j
指向了模式串末尾的下一个,在进行匹配的过程中,不难发现,当每次匹配失败后,i
指针都进行了不必要的回溯,这个回溯过程造成了时间的大量浪费。
2. KMP算法
1). KMP算法的优势
上文讲述了BF算法的实现,也阐述了BF算法的效率低下之处,KMP算法就是针对BF算法的改良,当进行模式匹配时,出现字符比较不等的情况,不用回溯i
指针,而是利用已经匹配过后的结果,向右尽可能滑动的稍远一些,再继续进行比较。
2). KMP算法的原理
以字符串Str = "acabaabaabcacaabc";
和 modStr = "abaabcac";
为例,进行说明:
当i=8, j=6
时,发现匹配失败: 如果按照BF算法, i
指针会回溯至4的位置重新开始比较。但是这种i
的回溯是有必要的吗?显然duck不必。
观察一下,j1=j4, j2=j5且i3=j1,i4=j2
,所以回溯i
指针到4的位置完全没有必要,根据上述等式关系,我们只需要将j
指针的位置移动到j4
的位置重新开始匹配。
再看一个例子: str=“aabababcaad” modStr=“babc”
,当i=6, j=4
时发生失配,但j1=j3
,所以直接将j
指针移动到j4
的位置,开始匹配。
再看最后一个例子,str=“aacabcd”, modStr=“abcd
,当发生失配时,怎么操作。
在发生失配时,将i指针向后移动一位,继续进行比较。
综合上述例子,不难看出模式串中存在着字符相同的元素,在模式串的子串中构成了前缀与后缀。并且在失配之后对于`i指针的移动存在一定的规律,从而引出了next数组的概念,next数组用于存放模式匹配失配时,模式串的滑动距离。
3). next数组的构造
通过上述的例子,已经得知next[]
数组存放的内容为,模式串与目标串匹配失败时用于寻找模式串回溯位置的数组。
如何计算next数组呢?其中最重要的概念就是最大前缀与最大后缀。
公式是这样表示最大前缀与最大后缀的,但是实际中如何求解呢。str="abaabcac"
以这个字符串为例,表示出它的前缀与后缀。
对于这个字符串它的前缀与后缀是这样的,所以它的最大前缀=最大后缀的字符串是a
;
接下来就要通过这个最大前缀=最大后缀的概念,来进行失配后模式串回溯的位置计算。
设模式串为abaabcac
( j
指向的位置为当前匹配位置,假设在当前位置失配,求出在当前位置失配的回溯位置,j
指针前方字符串为要计算回溯位置的子串)
1.j=1失配 (因为j=0 所以next[j]=0)
2.j=2失配 (没有前后缀,属于其他情况)
3.j=3失配(前缀不等与后缀)
4.j=4失配(最大前缀=最大后缀,所以k=2)
5.j=5失配
6.j=6失配 (最大前缀 ab = 最大后缀 ab, 所以k=3)
7.j=7失配
8.j=8失配
以上为next数组求法,但字符串下表一般从0开始,所以要对next数组中元素-1,得
至此,next数组已经求解完毕,如何利用next数组进行模式匹配,继续阅读下文。
4). 利用next数组匹配的过程
在这一部分,将会说明模式匹配是如何利用next数组进行模式匹配。
以str = "acabaabaabcacaabc";
和 modStr = "abaabcac";
为例,字符串下标从0开始,进行说明:
1.第一次匹配(i=1,j=1位置发生失配)
根据next数组可知,将j
指针回溯到j0
位置进行重新匹配。
2.第二次匹配(i=1,j=0位置发生失配)
next数组中没有相关跳转位置,所以i
指针后移一位,开始匹配。
3.第三次匹配(i=7,j=5位置发生失配)
根据next数组,可知j
回溯到 2
的位置重新开始匹配
4.匹配成功
以上就为KMP算法的匹配过程。
二. KMP算法的代码实现
1. 生成next[]数组
void getNextArr(string modelStr, int* next)
{// 初始化next数组第一位为-1int i = 0;int j = -1;next[0] = -1;int mLen = modelStr.length();while (i < mLen - 1){// 求最大前缀=最大后缀的过程if (j == -1 || modelStr[i] == modelStr[j]){i++;j++;next[i] = j;}else{// 当没有匹配上 则进行回溯 回溯的位置为next数组的指向的下一个匹配项j = next[j];}}
}
2. KMP查找过程代码
// 如果查找成功返回位置
// 如果查找失败返回-1
int KMP(string dstStr, string modelStr)
{int i = 0;int j = 0;int dstlen = dstStr.length();int modellen = modelStr.length();int next[255] = { 0 };getNextArr(modelStr, next);while ((i < dstlen) && (j < modellen)){if (j == -1 || dstStr[i] == modelStr[j]){i++;j++;}else{j = next[j];}}if (j >= modellen){return i - modellen; // 匹配成功 返回子串位置}else{return -1;}
}
[数据结构]模式匹配算法--KMP算法详解相关推荐
- 数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)
数据结构(C语言版)严蔚敏(字符串的模式匹配算法–KMP算法) 1.暴力匹配算法 // 暴力匹配算法 int Index2(SString S,SString T) {// S是主串,T是子串int ...
- KMP算法详解P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- KMP算法详解及代码
KMP算法详解及代码 KMP算法详解及代码 定义及应用 理论 基本概念 next 数组 总结 注意 代码 KMP算法详解及代码 最近正好在看字符串相关的算法内容,就顺便把KMP算法回顾了一下.相应的代 ...
- KMP算法详解及各种应用
KMP算法详解: KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字.其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题 ...
- 字符串匹配之KMP算法详解
kmp算法又称"看毛片"算法,是一个效率非常高的字符串匹配算法.不过由于其难以理解,所以在很长的一段时间内一直没有搞懂.虽然网上有很多资料,但是鲜见好的博客能简单明了地将其讲清楚. ...
- 奇淫巧技的KMP算法--详解
奇淫巧技的KMP算法–详解 花了一下午时间,看了十几个博客,终于拿下了KMP高地,现在总结下下自己对KMP的理解和实现. 情景1 假如你是一名生物学家,现在,你的面前有两段 DNA 序列 S 和 T, ...
- 【KMP算法详解——适合初学KMP算法的朋友】
相信很多人(包括自己)初识KMP算法的时候始终是丈二和尚摸不着头脑,要么完全不知所云,要么看不懂书上的解释,要么自己觉得好像心里了解KMP算法的意思,却说不出个究竟,所谓知其然不知其所以然是也. 经过 ...
- 【转】KMP算法详解
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任. http://billhoo.blog.51cto.com/2337751/411486 ...
- 【数据结构Note4】-串、数组和广义表(kmp算法详解)
文章目录 串.数组和广义表 1. 串 1.1 串的概念和结构 1.2 顺序串和链串 1.3 BF算法--串的模式匹配法之一 1.5 KMP算法--串的模式匹配法之一 1.5.1 next数组 1.5. ...
最新文章
- [分享]组织机构图控件
- 数据库事务的四大特性以及事务的隔离级别
- 写文件 —— 将内容按照指定格式写入配置文件(fwrite()函数-》》向指定的文件中写入若干数据块)
- HTTP_响应消息_响应行_状态码
- 关于iPhone的UIView刷新(转)
- linux php oauth安装,Linux php 扩展安装 mongo ,redis ,soap,imap,pdo_mysql,oauth
- 服务器显示配置命令,linux查看服务器配置命令
- (CSDN迁移) 输入一个链表,从尾到头打印链表每个节点的值
- javascript中的滚动到顶部和Scroll有关的方法
- 工程测量计算机在线用,工程测量中的计算机编程新技术.doc
- php网页弹窗广告,弹窗广告最多的网站
- python-onvif库基本使用
- 基于JavaFx的通讯录
- CMSC5724-数据挖掘之VC维、Shatter、VC-dim以及Margin有关的通理
- 花生壳域名穿透 网站无法访问
- 关于Adobe2017-2022安装包在win11打开后没有安装按钮的解决方案,AE,PS,PR,DW,通用解决方法
- 从键盘输入一个英文字母,如果它是大写英文字母,则将其转换为小写英文字母,如果它是小写英文字母,则将其转换为大写英文字母,然后将它及其ASCII码值显示到屏幕上,如果不是英文字母,则不转换直接输出到屏幕
- 如何选择美颜SDK接口?
- 机器人控制算法四之迭代法求解四轴机器人逆解
- 宁德时代打响增长保卫战