KMP算法--字符串模式匹配算法
今天看到第四章《串》了,其中我觉得花的时间多一点的值得我写篇随笔的知识点就是:4.3 串的模式匹配算法;书上介绍了两种字符串匹配算法,一种是最简单最容易想到的逐个字符匹配算法(时间复杂度在好的情况下为O(n+m),[n为原串,m为匹配串],在最坏的情况下为O(n*m)),这个在我的代码中有了,就不赘述了。另外一种就是KMP算法,话说是三个人同时想到的算法,这仨名字各取开头的字符就是这个算法的名称了。这个算法是模式匹配的改进算法;(时间复杂度为O(m))。
1 int indexOf(string s,string t,int pos){//逐个字符匹配算法,从s串的pos位置开始,返回t出现的首位置 2 if(t.empty()){//字串不要为空 3 return -1; 4 } 5 int i = pos; 6 int temp = 0; 7 for(;i<s.size();i++){ 8 temp = i; 9 for(int j = 0;j<t.size();j++){10 if(s[temp] == t[j]){//如果相等,就继续循环下去11 temp++;12 if(j == (t.size()-1)){13 return i;//返回出现的首位置14 }15 }else{//不相等16 break;17 }18 }19 }20 }
而这个KMP算法在大体思想就是这样:
注意: s为原串,t为模式串,即小一点的那个,后面都是一样。↑↓
↓i=0 从这儿开始比较
1.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c (红色为t在s中第一次出现)
↑j=0 next[0]=-1 (next[]数组的作用等会儿说哈)
↓i=1
2.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c
↑j=1 next[1]=0 (发现c!=b,所以t串又要从头来比较,后面的代码就如下,j = next[j]; if(j==-1){j=0;)
↓i=1
3.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c
↑j=1 next[1]=0 (发现c!=a,所以s串又要后退点了)
↓i=2
4.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c
↑j=0 next[0]=-1 (相等,好的继续)
↓i=7
5.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c
↑j=5 next[5]=2 (发现c!=a了,这时候就是体现算法的时候了,此时i会暂停向后移动,而t串应该从哪里开始比较呢?next数组告诉了我们答案,从t[2]开始和s串i位置开始比较,如下图)
↓i=7
6.s : a c a b a a b a a b c a c a a b c
t : a b a a b c a c
↑j=2 next[2]=0 (后面的移动方式我没必要画了,很明显已经移到合适的地方了,乍一看很巧,细细一想还是很有智慧的)
好,我来说说上面出现的每个参数的作用吧:s为原串,t为模式串,i为s串的移动指针,j为t串的移动指针,next数组的作用是指明t串指针j的位置的,也就是j回溯多少,当S串中的第i个字符与t串中的第j个字符不等时,s串的第i个字符(i指针永远不会往回走,最多只是暂停下)应该与模式中的哪个字符再比较的。针对每个t串,都会生成相对应的next数组,而next如何生成?
请看next特征数组构造:
模式串t开头的任意个字符,把它称为前缀子串,如t0t1t2…tm-1。在t的第i位置的左边,取出k个字符,称为i位置的左子串,即ti-k+1... ti-2 ti-1 ti。求出最长的(最大的k)使得前缀子串与左子串相匹配称为,在第i位的最长前缀串。第i位的最长前缀串的长度k就是模板串P在位置i上的特征数n[i]特征数组成的向量称为该模式串的特征向量。
可以证明对于任意的模式串t = t0t1…tm-1,确实存在一个由模式串本身唯一确定的与目标串无关的数组next,计算方法为:
(1) 求t0…ti-1中最大相同的前缀和后缀的长度k;
(2) next[i] = k;
作为特殊情况,当i=0时,令next[i] = -1;显然,对于任意i(0≤i<m),有next[i] < i;假定已经计算得到next[i], 那么next[i+1] = ? 特征数ni ( -1≤ ni ≤ i )是递归定义的,定义如下:
(1) n[0] = -1,对于i > 0的n[i] ,假定已知前一位置的特征数 n[i-1]= k ;
(2) 如果ti = tk ,则n[i] = k+1 ;
(3) 当ti ≠ tk 且k≠0时,则令k = n [k -1] ; 让(3)循环直到条件不满足;
(4) 当qi ≠ qk 且k = 0时,则ni = 0;
根据以上分析,可以得到next特征数组的计算方法,算法代码如下:
1 void getNext(string t,int* next){//求子字串t的next[]函数之并存入数组中 2 int temp = 0; 3 int zm = 0; 4 for(int i = 0; i < t.size();i++){//从0开始循环 5 temp = i-1; 6 if(i == 0){//第一个的时候,为-1 7 next[i] = -1; 8 }else if(temp > 0){ 9 for(int j = temp;j>0;j--){10 if(equals(t,i,j)){11 next[i] = j;12 break;13 }else{14 next[i] = 0;//视为其他情况为015 continue;16 }17 18 }19 }else{20 next[i] = 0;//其他情况为021 }22 23 }24 25 }26 27 bool equals(string t,int i,int j){//比较字符串t[0]~t[j-1]同t[i-j]~t[j]是否相等28 int temp = i-j;29 //if((j-1)==(2*j-i)){//如果长度相同30 for(int k = 0; k < j; k++,temp++){31 if(t[k]!=t[temp]){//如果有不相同的,返回false32 return false;33 }34 }35 return true;//运行到这儿说明字符串t[0]~t[j-1]同t[i-j]~t[j]相等36 }
到这里了,解决了一个点了,还有一个点就是,i串既然不回溯,还是有暂停的,至于暂停总是有这样规律的:第一不匹配--停,第二次不匹配--走...针对i串的同一个字符没有第三次哦,为什么?你懂的。
说到这儿,我想KMP算法的思想应该讲完了,看起来KMP算法是要好些,通常来说,模式串t的长度比S串的小的多,对于整个匹配算法来讲,确实要改进不少,虽然第一种算法的时间复杂度是O(n*m),但是在一般的情况下,其实际执行的时间按近似于O(n+m),所以至今很多地方也有采用;
总结:KMP算法在模式串t与主串s存在许多“部分匹配”的情况下才显得速度很快,这个算法的最大特点就是,主串的指针不需要回溯,从头扫一遍就行了,这对处理庞大的数据文件很有效,也可以边读入便匹配,无需回头再重读。
忘记贴代码了,呵呵,补上:
1 /* 2 2011-7-25 zhangming 3 第四章,串 4.3节-串的模式匹配算法 4 总的来说有两种算法, 5 1,逐个字符匹配算法;(此匹配算法最简单,时间复杂度在好的情况下为O(n+m),[n为原串,m为匹配串],在最坏的情况下为O(n*m)) 6 2,KMP算法;模式匹配的改进算法;(时间复杂度为O(m)) 7 */ 8 #include <iostream> 9 #include <string> 10 using namespace std; 11 int indexOf(string s,string t,int pos);//逐个字符匹配算法,从s串的pos位置开始,返回t出现的首位置 12 int indexOfKMP(string s,string t,int pos);//KMP算法;模式匹配的改进算法; 13 void getNext(string t,int* next);//求子字串t的next函数之并存入数组中 14 bool equals(string t,int i,int j);//比较字符串t[0]~t[j-1]同t[i-j]~t[j]是否相等 15 void main(){ 16 string s = "acabaabaabcacaabc"; 17 string t = "abaabcac"; 18 cout<<t<<"出现在"<<s<<"的第"<<indexOf(s,t,2)+1<<"位置。\n"; 19 cout<<t<<"出现在"<<s<<"的第"<<indexOfKMP(s,t,2)+1<<"位置。\n"; 20 system("pause"); 21 } 22 23 int indexOf(string s,string t,int pos){//逐个字符匹配算法,从s串的pos位置开始,返回t出现的首位置 24 if(t.empty()){//字串不要为空 25 return -1; 26 } 27 int i = pos; 28 int temp = 0; 29 for(;i<s.size();i++){ 30 temp = i; 31 for(int j = 0;j<t.size();j++){ 32 if(s[temp] == t[j]){//如果相等,就继续循环下去 33 temp++; 34 if(j == (t.size()-1)){ 35 return i;//返回出现的首位置 36 } 37 }else{//不相等 38 break; 39 } 40 } 41 } 42 } 43 int indexOfKMP(string s,string t,int pos){//KMP算法;模式匹配的改进算法; 44 if(t.empty()){//t字串不要为空 45 return -1; 46 } 47 int* next = new int[t.size()]; 48 int pause = 0;//控制是否暂停的 49 getNext(t,next); 50 int i = 0,j = 0; 51 while(i!=s.size()){ 52 if(s[i]==t[j]){ 53 i++; 54 j++; 55 }else{ 56 if(pause==1){//如果不需要暂停 57 pause=0; 58 i++; 59 }else{//如果需要暂停 60 pause=1; 61 } 62 j = next[j]; 63 if(j==-1){ 64 j=0; 65 } 66 } 67 if(j==t.size()){ 68 return i-t.size(); 69 } 70 } 71 return -1; 72 } 73 void getNext(string t,int* next){//求子字串t的next[]函数之并存入数组中 74 int temp = 0; 75 int zm = 0; 76 for(int i = 0; i < t.size();i++){//从0开始循环 77 temp = i-1; 78 if(i == 0){//第一个的时候,为-1 79 next[i] = -1; 80 }else if(temp > 0){ 81 for(int j = temp;j>0;j--){ 82 if(equals(t,i,j)){ 83 next[i] = j; 84 break; 85 }else{ 86 next[i] = 0;//视为其他情况为0 87 continue; 88 } 89 90 } 91 }else{ 92 next[i] = 0;//其他情况为0 93 } 94 95 } 96 97 } 98 bool equals(string t,int i,int j){//比较字符串t[0]~t[j-1]同t[i-j]~t[j]是否相等 99 int temp = i-j;100 //if((j-1)==(2*j-i)){//如果长度相同101 for(int k = 0; k < j; k++,temp++){102 if(t[k]!=t[temp]){//如果有不相同的,返回false103 return false;104 }105 }106 return true;//运行到这儿说明字符串t[0]~t[j-1]同t[i-j]~t[j]相等107 }
转载于:https://www.cnblogs.com/silence250627170/archive/2011/07/25/2116666.html
KMP算法--字符串模式匹配算法相关推荐
- KMP算法 -- 字符串模式匹配算法
KMP算法 复杂度O(m+n) 查找某个字符串是否被另一个字符串包含 原理可以见: http://news.cnblogs.com/n/176771/ 代码出自<<大话数据结构>&g ...
- Problem C: 算法4-6:KMP字符串模式匹配算法实现
Problem Description KMP算法是字符串模式匹配算法中较为高效的算法之一,其在某次子串匹配母串失败时并未回溯母串的指针而是将子串的指针移动到相应的位置.严蔚敏老师的书中详细描述了KM ...
- 数据结构——基于字符串模式匹配算法的病毒感染检测
实验四 基于字符串模式匹配算法的病毒感染检测 [实验目的] 1.掌握字符串的顺序存储表示方法. 2.掌握字符串模式匹配BF算法和KMP算法的实现. [实验内容] 问题描述 医学研究者最近发现了某些新病 ...
- 数据据结构实验4《基于字符串模式匹配算法的病毒感染检测》
(visual studio 2019可运行) 输入及输出要求见<数据结构C语言(第二版)>严蔚敏版 [本文仅用于啥都看不懂还想交作业选手] //KMP求解基于字符串模式匹配算法的病毒感染 ...
- 【数据结构】字符串 模式匹配算法的理解与实现 Brute Force算法(BF算法)与KMP算法 (C与C++分别实现)
#笔记整理 若不了解串的定义,可至: 串(string)的定义与表示 查看 串的模式匹配算法 求子串位置的定位函数 Index(S, P, pos) 求子串的定位操作通常称作串的模式匹配(其中子串P称 ...
- 基于字符串模式匹配算法的病毒感染检测问题(KMP算法)
头文件(tou.h): void get_next(char T[], int next[]);int Index_KMP(char S[], char T[]);void move1(char a[ ...
- 【2023王道数据结构】【字符串匹配算法】字符串的KMP(next数组)模式匹配算法C、C++完整实现(可直接运行)
~~~笔锋至此又怎能平淡而终,故事开始便不承认普通✌✌✌ ✌ 题目及题解持续更新中 [2023王道数据结构目录]课后算法设计题C.C++代码实现完整版大全 题目: 字符串的KMP(next)模式匹配算 ...
- KMP字符串模式匹配算法【精简代码模板】
什么是模式匹配 模式匹配(Pattern Matching)就是在一篇长度为n的文本S中,找某个长度为m的关键字P. KMP算法如何来的? KMP算法是由朴素字符串匹配算法优化而来,就是重新利用了朴素 ...
- KMP算法字符串模式匹配
KMP字符串模式匹配详解 来自CSDN A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算 ...
最新文章
- linux文件属性解析,Linux操作系统的文件属性与目录配置解析
- SQL SERVER 2005 CTE(通用表达式)
- 搜索背后的奥秘——浅谈语义主题计算
- 四.jmeter代码学习, SampleResult【持续更新】
- Angular Forms - 自定义 ngModel 绑定值的方式
- 企业QQ 增加在线交谈链接
- 热敏电阻温度特性曲线_热敏电阻与体温计的应用关系
- 轨迹规划实现 tfaar_example2.7
- nullnullicon 小图标
- HDU-3374 String Problem (最小表示法)
- 利用XML实现通用WEB报表打印(参考)
- Eclipse配置中文(汉化)
- 【U3D】推荐一些不错的Unity游戏开发素材资源
- CDA LEVELⅠ2021新版模拟题一(附答案)
- matlab菲涅尔衍射光强分布,矩孔菲涅耳衍射的光强分布.pdf
- Linux学习—编译
- Xp系统优化 预读文件(8)
- Python学习(七)if语句
- 抖音直播用什么手机效果最好 抖音直播手机哪款好2023
- 自然语言处理2——语言学基础
热门文章
- 可视化日历(Java实现)
- 数学之路(2)-数据分析-R基础(4)
- java list set map的区别_Java集合类List/Set/Map的区别和联系
- erlang精要(13)-基本语法(1)
- hinton、李飞飞支持的NLP明星创企,今获1.25 亿美元B轮融资
- 【数据竞赛】懒人特征筛选算法!
- 【算法基础】数据结构导论第六章-查找.pptx
- 【CV】54篇最新CV领域综述论文速递!涵盖14个方向:目标检测/图像分割/医学影像/人脸识别等方向...
- NLP深度学习:PyTorch文本分类
- CVPR2019最全整理:全部论文下载,Github源码汇总、直播视频、论文解读等