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

主要是针对字符串的匹配算法进行解说


  • 有关字符串的基本知识
  • 传统的串匹配法
  • 模式匹配的一种改进算法KMP算法
    • 网上一比較易懂的解说
    • 小样例
    • 1计算next
    • 2计算nextval
    • 代码

有关字符串的基本知识

串(string或字符串)是由零个或多个字符组成的有限序列,一般记为这里写图片描写叙述 当中s是串的名,用单引號括起来的字符序列是串的值;ai(1<=i<=n)能够是字母、数值或其它字符。串中字符的数组 n称为串的长度。零个字符的串称为空串,它的长度为0

串中随意个连续的字符组成的子序列称为该串的子串。

包括子串的串相应的称为主串。

通常称字符在序列中的序号为该字符在串中的位置。子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。

以下主要说一下串的模式匹配算法

传统的串匹配法

算法的基本思想是:从主串S的第pos个字符起和模式的第一个字符比較,若相等,则继续逐个比較兴许字符;否则从主串的下一个字符起再又一次和模式的字符比較。依次类推,直至模式T中的每一个字符依次和主串S中的一个连续的字符序列相等,则匹配成功,函数值为和模式T中第一个字符相等的字符在主串S中的序号,否则称匹配不成功。函数值为零。
此算法在最坏情况下的时间复杂度为O(m*n)

模式匹配的一种改进算法(KMP算法)

网上一比較易懂的解说

字符串匹配的KMP算法

字符串匹配是计算机的基本任务之中的一个。
举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包括还有一个字符串”ABCDABD”?

很多算法能够完毕这个任务,Knuth-Morris-Pratt算法(简称KMP)是最经常使用的之中的一个。它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth。

以下,我用自己的语言,试图写一篇比較好懂的KMP算法解释。
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”的位置。


小样例

求字符串 ‘ababaabab’的next和nextval,结果例如以下

j123456789
s[ j ]ababaabab
next011234234
nextval010104101

(1)计算next

计算next的时候须要遵循的规则例如以下

A、 j = 0 next[j] = 0
B、假设存在 Max{ k | k 属于 (1,j-1) 且‘P1…Pk-1’= ‘Pj-k+1…Pj-1’ } (next[j] = k)
C、其它情况 next[j] = 1

j( 1, k-1 )str(1,k-1)( j-k+1 , j-1 )str( j-k+1, j-1)规则next[ j ]
2NULLNULLNULLNULLC1
3(1,1)a(2,2)bC1
4(1,2)ab(2,3)ba
4(1,1)a(3,3)aB2
5(1,3)aba(2,4)bab
5(1,2)ab(3,4)abB3
6(1,4)abab(2,5)baba
6(1,3)aba(3,5)abaB4
7(1,5)ababa(2,6)babaa
7(1,4)abab(3,6)abaa
7(1,3)aba(4,6)baa
7(1,2)ab(5,6)aa
7(1,1)a(6,6)aB2
8(1,6)ababaa(2,7)babaab
8(1,5)ababa(3,7)abaab
8(1,4)abab(4,7)baab
8(1,3)aba(5,7)aab
8(1,2)ab(6,7)abB3
9(1,7)ababaab(2,8)babaaba
9(1,6)ababaa(3,8)abaaba
9(1,5)ababa(4,8)baaba
9(1,4)abab(5,8)aaba
9(1,3)aba(6,8)abaB4

(2)计算nextval

nextval[i]的求解须要比較s中next[i]所在位置的字符是否与s[i]的字符一致。假设一致则用s[next[i]]的nextval的值作为nextval[i]。假设不一致,则用next[i]做为nextval[i]。

inext[i]s[i]s[ next[i] ]yes/nonextval[i]
10aNULLnonext[i] = 0
21banonext[i] = 1
31aayess[ next[i] ]的nextval = 0
42bbyess[2]nextval = 1
53aayess[2]nextval = 0
64abnonext[6] = 4
72bbyess[2] nextval = 1
83aayess[3] nextval = 0
94bbyess[4]nextval = 1

代码

该代码參考 数据结构(C语言版) 严蔚敏 吴伟民 编著。。。

/*** @filename      kmp.cc* @Synopsis      KMP algorithm * @author       XIU* @version      1* @date         2016-04-21*/
// 此代码中所用的数组,或者是字符串都是从下标1開始#include<iostream>
#include<string.h>using namespace std;/* ============================================================================*/
/*** @Synopsis      the next index data of the model string s_mode** @Param         s_mode: the string* @Param         next  : the next array* @Param         len   : the length of the string*/
/* ============================================================================*/
void get_next( string s_mode, int *next, int len )
{int i = 1;int j = 0;next[1] = 0;//cout << len << endl;while( i<len ){if( j==0 || s_mode[i] == s_mode[j] ){++i;++j;if( i>len ) break;next[i] = j;if( j>len ) break;//以下的是修正的next算法(nextval)。/*if( s_mode[i] != s_mode[j]) next[i] = j;else next[i] = next[j];*/}else{j = next[j];}}for( int i=1; i<len; i++ ){cout << next[i] << " ";}cout << endl; }/* ============================================================================*/
/*** @Synopsis      利用模式串s_mode中的next函数求s_model在主串 s_primary中第pos个字符之后的位置** @Param         s_primary* @Param         s_mode* @Param         pos* @Param         next** @Returns       */
/* ============================================================================*/
int Index_KMP( string s_primary, string s_mode, int pos, int *next )
{int i = pos;int j = 1;int len_p = s_primary.size();int len_m = s_mode.size();while( i < len_p && j < len_m ){if( j == 0 || s_primary[i] == s_mode[j] ){++i;++j;}elsej = next[j];}if( j >= len_m )return i - len_m;elsereturn 0;
}/* ============================================================================*/
/*** @Synopsis      output function to check the result** @Param         s_primary* @Param         s_mode* @Param         len* @Param         next* @Param         index*/
/* ============================================================================*/
void output( string s_primary, string s_mode, int len, int *next, int index )
{cout << "s_primary = " << s_primary << endl;cout << "s_mode = " << s_mode << endl;for( int i=1; i<len; i++ ){cout << next[i] << " ";}cout << endl; cout << "index = " << index << endl;}
int main()
{string s_primary = " acabaabaabcacaabc";string s_mode    = " abaabcac";int len = s_mode.size() ;int *next = new int[len];get_next( s_mode, next, len );int tmp = Index_KMP( s_primary, s_mode, 1, next );output( s_primary, s_mode, len, next, tmp );delete [] next;return 0;
}

參考网址
【1】字符串匹配的KMP算法 - 阮一峰的网络日志
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
【2】KMP算法具体解释 - joylnwang的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/joylnwang/article/details/6778316
【3】经典算法研究系列:六、教你初步了解KMP算法、updated - 结构之法 算法之道 - 博客频道 - CSDN.NET
http://blog.csdn.net/v_JULY_v/article/details/6111565


转载于:https://www.cnblogs.com/lxjshuju/p/7248686.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

serialVersionUID的作用以及如何用idea自动生成实体类的serialVersionUID

转载&#xff1a;http://blog.csdn.net/liuzongl2012/article/details/45168585 serialVersionUID的作用&#xff1a; 通过判断实体类的serialVersionUID来验证版本一致性的。在进行反序列化时&#xff0c;JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVer…

JBoss BRMS最佳实践– BPM流程初始化层的提示

我过去发布过一些有关迁移策略的文章&#xff0c;仔细研究了流程层&#xff0c;并提供了一些有关jBPM的最佳实践 &#xff0c;它们都涉及到BPM策略的非常具体的部分。 我想重新讨论最佳实践的主题&#xff0c;然后在智能集成企业级别上&#xff0c;我们讨论使用JBoss BRMS对您的…

跨站点脚本(XSS)和预防

如OWASP网站&#xff08;https://www.owasp.org/index.php/Cross-site_Scripting_(XSS&#xff09;&#xff09;所述&#xff0c;跨站点脚本&#xff08;XSS&#xff09;攻击的变种几乎是无限的。 在这里&#xff0c;我建议使用基于Servlet筛选器的解决方案来清理HTTP请求。 攻…

NoSQL入门第一天——NoSQL入门与基本概述

一、课程大纲 二、入门概述 1.为什么用NoSQL 单机MySQL的年代&#xff1a; 一个网站的访问量一般都不大&#xff0c;用单个数据库完全可以轻松应付。      我们来看看数据存储的瓶颈是什么&#xff1f;        1.数据量的总大小 一个机器放不下时。&#xff08;现…

C语言结构体及函数传递数组參数演示样例

C语言结构体及函数传递数组參数演示样例 注&#xff1a;makeSphere()函数返回Sphere结构体&#xff0c;main函数中。调用makeSphere()函数&#xff0c;传递的第一个參数为数组&#xff0c;传递的数组作为指针。posted on 2017-07-30 18:42 mthoutai 阅读(...) 评论(...) 编辑 收…

AIX下RAC搭建 Oracle10G(六)dbca建库

AIX下RAC搭建系列 AIX下RAC搭建 Oracle10G&#xff08;六&#xff09;dbca建库 环境 节点 节点1 节点2 小机型号 IBM P-series 630 IBM P-series 630 主机名 AIX203 AIX204 交换机 SAN光纤交换机 存储 SAN T3存储 大纲流程例如以下&#xff1a; 第一部分&#xff1…

JavaOne 2012:掌握Java部署

在吃完一次JavaClass 2012午餐会的意大利经典组合后&#xff0c;我前往希尔顿帝国宴会厅B观看了演示“掌握Java部署”。 来自Oracle的发言人是Mark Howe和Igor Nekrestyano Howe表示&#xff0c;部署团队的目标是帮助Java开发人员将其应用程序部署到所选平台。 他首先讨论了“功…

php 提高吞吐量,如何提高网站的吞吐量

吞吐量定义百科吞吐量是指对网络、设备、端口、虚电路或其他设施&#xff0c;单位时间内成功地传送数据的数量(以比特、字节、分组等测量)。以上的定义比较宽泛&#xff0c;定义到网站或者接口的吞吐量是这样的&#xff1a;吞吐量是指系统在单位时间内处理请求的数量。这里有一…

使用您自己的规则在Eclipse中自定义PMD

PMD是非常好的Java代码扫描程序&#xff0c;可帮助您避免潜在的编程问题。 它可以轻松扩展以满足您的需求&#xff0c;并且本文将为您带来与JPA的Enumerated注释用法相关的自定义PMD规则的简单示例。 在继续阅读之前&#xff0c;您应该检查我以前的文章之一-JPA-Enumerated def…

yii2之DetailView小部件

DetailView小部件用于展示单条数据记录&#xff0c;可配置属性很少&#xff0c;使用也很简单&#xff0c;直接贴代码&#xff0c;一看就懂&#xff01; yii小部件数据小部件DetailView的使用示例&#xff1a; <? DetailView::widget([model > $user,//模型对象&#xff…

gitlab的安装和基本维护

基本介绍 GitLab是一个自托管的Git项目仓库&#xff0c;可以自己搭建个人代码管理的仓库&#xff0c;功能与github类似。 安装 操作系统&#xff1a;CentOS6.5 gitlab官网下载安装地址&#xff1a;https://about.gitlab.com/downloads/#centos6 1.安装依赖的包 yum install cur…

unity中怎么在InspectorI面板加LOGO

转载于:https://www.cnblogs.com/unitySPK/p/7278925.html

重写到边缘–充分利用它! 在GlassFish上!

现代应用程序开发的一个重要主题是重写。 自从Java Server Faces引入和Java EE 6中新的轻量级编程模型以来&#xff0c;您一直在努力使用漂亮&#xff0c;简单&#xff0c;可添加书签的URL。 PrettyFaces很久以来就一直存在&#xff0c;即使它在3.3.3版本中可以说是成熟的&…

php yii框架路由,yii框架路由配置

首先要在服务器配置(httpd.conf)中开启重写模块#开启重写模块&#xff0c;将其前面的#去掉LoadModule rewrite_module modules/mod_rewrite.so#Directory中允许覆盖开启## Possible values for the Options directive are "None", "All",# or any combinat…

前端面试总结二

一、响应式和自适应的区别&#xff1a; 联系(相同点)&#xff1a; 响应式设计(responsive design)和自适应设计(adaptive design)都是用来解决网页在不同分辨率的屏幕和设备上展示的一项技术(或者说一种方法)。 区别&#xff1a; 响应式设计&#xff1a;通过CSS Media Queries(…

【看番杂感】Clannad系列观后感(剧透慎入)

前言 之前看第一季时&#xff0c;弹幕里总有人在刷“写作cl&#xff0c;读作人生”。当时我想&#xff0c;盲目把一部催泪番上升到人生的高度&#xff0c;这未免有些武断&#xff0c;也是对作品本身的不尊重。当看完第二季的我蓦然回首&#xff0c;发现这才是最最贴切的评价&am…

Centos7 开机显示 ERST: Failed to get Error Log Address Range” 导致无法开机解决方法

开机显示 ERST: Failed to get Error Log Address Range” 导致无法开机&#xff0c;也无法重新安装系统&#xff0c;解决方法&#xff1a;开机进入BIOS &#xff0c; 关闭ACPI选项即可正常开机 转载于:https://www.cnblogs.com/zhangjianghua/p/6376811.html

Spring MVC 3模板和Apache Tiles

对于任何Web应用程序而言&#xff0c;有效的设计考虑因素是使用模板引擎&#xff08;或工具&#xff09;&#xff0c;并且由于具有Spring的“可插拔”特性&#xff0c;因此集成模板机制&#xff08;例如Apache Tiles&#xff09;的确要容易得多。 在这篇简单的文章中&#xff0…

js 判断浏览器是否64位

js判断是否64位 浏览器 navigator.userAgent.match(/x64/i); 转载于:https://www.cnblogs.com/fanlinglong/p/7298733.html

浙江大学linux网络通信,浙江大学钟财军副教授——“Wireless Powered Communication Networks”...

2016年5月17日&#xff0c;浙江大学钟财军副教授应徐正元教授邀请在中科大西区科技实验楼东楼十层1011会议室做了一场题为“Wireless Powered Communication Networks”的学术报告。报告会由龚晨教授主持&#xff0c;共50余名师生参加。此次报告会得到了“中科院无线光电通信重…