KMP(Knuth-Morris-Pratt)算法,详细版

2024-03-22 11:10

本文主要是介绍KMP(Knuth-Morris-Pratt)算法,详细版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

KMP(Knuth-Morris-Pratt)算法

1、KMP算法

在目标串T中搜索模式串P

​ 由于强制算法(暴力搜素算法)在找到不匹配的字符时,只能把模式串P(相对于目标串T)移动一个位置,导致大量的操作重复,冗余的次数随目标串,或模式串长度的增长,使得代码的执行效率直线下降。

​ 为了使搜素的效率提高,且不遗漏每一处匹配,KMP算法通过利用匹配失败处的位置信息,进行改进,使失败的匹配结果也能得到利用,加快字符串匹配效率

2、过程

2.1、给定目标串T,和模式串P

注意:一个字符串的前缀可以包括其本身

   0 1 2 3 4 5 6 7 8 9 10 11
T: a b c a b d a b a b c d
P: a b a b c

2.2、对模式串P创建前缀表PrefixTable

  模式串P前缀    最长公共前后缀       最长公共前后缀长度  index       prefix[index]
----------------------------------------------------------------------------------------
-1|          |      -          |        -        |  0	 |       -1      |
0 |	a        |     null        |        0        | 	1	 |        0      |
0 |	a b      |     null        |        0        |  2	 |        0      |
1 |	a b a    |      a          |        1        |  3	 |        1      |
2 |	a b a b  |      ab         |        2        |  4	 |        2      |
- |	a b a b c|     null        |        0        |  -	 |         -     |这一行不要

2.2.1具体操作:

  1. 写出模式串的前缀(由于包含本身)
  2. 根据模式串的前缀,写出对应的最长公共前后缀长度[0 0 1 2 0]
  3. [0 0 1 2 0],去掉最后一个元素,整体向右移动,在最前面写**-1**-------->[-1 0 0 1 2 ]

2.2.2得到前缀表

P: a  b  a  b  c-1  0  0  1  2  <---a下面应该是0,为了代码写起来方便写成-1

2.3 KMP进行过程

2.3.1、

外链图片转存失败(img-0hJ5lPEz-1567419238965)(![C:\Users\张腾森\Desktop\算法\j1.png)]

​ 1.当模式串P和目标串T匹配到第4个字符时,T[3] != p[3],这时注意到P串下面的与P串相对应的前缀表内容,取出prefix[3] == 1,然后把P串的p[ prefix[3] == 1 ]去和T[3]做比较。

​ 总结1-1:当模式串P[j]和目标串T[i]不匹配时**(i任意取的,完全是模式串在目标串上移动的,所以p串可能匹配t串的任意位置)**,获取P串对应的下标j,在用相同的下标j去获取前缀表中的内容int k = prefix[j]
然后用p[k]去和T[i]匹配,

[外链图片转存失败(img-Bi6PM7OZ-1567419238968)(C:\Users\张腾森\Desktop\算法\j2.png)]

​ 2.此时会发现,p[1]==b,t[3]==1;p[1]!=t[3],不匹配,于是继续上面的操作,在模式串P中取出不匹配处的下标·j==0,在通过该下标去获取前缀表的内容prefix[j==0]==0,再用p[0]去和t[3]做匹配

[外链图片转存失败(img-gbgHsZS8-1567419238970)(C:\Users\张腾森\Desktop\算法\j3.png)]

​ 3、发现p[0]==T[3],这时,移动目标串T的位置t[3---->4]p[0---->1],于是用T[4]==c,与p[0]==b进行匹配,发现T[4]!=p[1],重复第二步,获取模式串P在不匹配处的下标j==1,在通过该下标j==1找到前缀表中对应的值prefix[j==1]==0,于是用模式串j==0节点P[j==0]去对应t[4],

​ 总结1-2:当模式串P和目标串T同时匹配上时,目标串T和模式串P移动到下一个节点(i++,j++)进行匹配,如果不匹配,则重复总结1-1

4.注意到,p[1]==b;t[4]==c;是不匹配的,于是去前缀表prefix[1]==0;于是用p[0]==a去和t[4]==c去匹配,结果还是不匹配,**此时在去前缀
表取值发现prefix[0]== -1,这时候要做的就是用P[-1]==?去和t[4]==c做匹配,换就话说,就是把整个p串右移一个位置,和t的下一个元
素进行匹配(i++,j++)**

[外链图片转存失败(img-1kZPeIfU-1567419238973)(C:\Users\张腾森\Desktop\算法\j5.png)]

​ 5,继续匹配后,发现已经找到了第一个匹配成功的位置,此时返回在目标串中的当前索引位置i-模式串的长度

即第一个匹配成功的位置,

[外链图片转存失败(img-4mhtA7nn-1567419238974)(C:\Users\张腾森\Desktop\算法\j8.png)]

​ 6.当匹配成功时p的当前索引是4,于是取前缀表prefix[4]==2,再用p[2]==a,去和T串匹配,结果发现,到最和一个元素了(有可能出界),匹配结束。

[外链图片转存失败(img-qrPPNass-1567419238974)(C:\Users\张腾森\Desktop\算法\j9.png)]

3、代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void prefix_table(char pattern[], int prefix[], int n) {prefix[0] = 0;int len = 0;int	i =1;	while(i<n){if ( pattern[i] == pattern[len] ) {len++ ;prefix[i] = len;i++ ;}else {if(len > 0){len = prefix[ len-1];}else {prefix[i] = len;i++ ;}}}
}
void move_prefix_table(int prefix[], int n) {int i;for(i=n-1;i>0;i--){prefix[i] = prefix[i-1];}prefix[0] = -1;
}
void kmp_search( char text[], char pattern[]) {int n = strlen( pattern);//<----string.hint m = strlen( text );int* prefix =(int*)malloc( n*sizeof(int));//<--stdlib.h//int prefix[n]; prefix_table(pattern, prefix, n);move_prefix_table(prefix, n);
// text[i], Len( text)=m
// pattern[j] ,Len(pattern) = nint i=0;int j=0; while(i<m){if (j==n-1&&text[i]==pattern[j]) {printf("Found pattern at %d\n", i - j);j=prefix[j]; }if (text[i] == pattern[j]) {i++; j++;}else {j= prefix[j];if (j == -1) {i++; j++ ;}}}
} int main() {char pattern[] = "ABABCABAA";char text[]= "ABABABCABAABABABAB";kmp_search(text,pattern);return 0;
}

4、结果

[外链图片转存失败(img-shaFlpm4-1567419238980)(C:\Users\张腾森\Desktop\算法\j10.png)]

这篇关于KMP(Knuth-Morris-Pratt)算法,详细版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/835182

相关文章

最新版IDEA配置 Tomcat的详细过程

《最新版IDEA配置Tomcat的详细过程》本文介绍如何在IDEA中配置Tomcat服务器,并创建Web项目,首先检查Tomcat是否安装完成,然后在IDEA中创建Web项目并添加Web结构,接着,... 目录配置tomcat第一步,先给项目添加Web结构查看端口号配置tomcat    先检查自己的to

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

SpringBoot集成SOL链的详细过程

《SpringBoot集成SOL链的详细过程》Solanaj是一个用于与Solana区块链交互的Java库,它为Java开发者提供了一套功能丰富的API,使得在Java环境中可以轻松构建与Solana... 目录一、什么是solanaj?二、Pom依赖三、主要类3.1 RpcClient3.2 Public

手把手教你idea中创建一个javaweb(webapp)项目详细图文教程

《手把手教你idea中创建一个javaweb(webapp)项目详细图文教程》:本文主要介绍如何使用IntelliJIDEA创建一个Maven项目,并配置Tomcat服务器进行运行,过程包括创建... 1.启动idea2.创建项目模板点击项目-新建项目-选择maven,显示如下页面输入项目名称,选择

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Spring Boot 中整合 MyBatis-Plus详细步骤(最新推荐)

《SpringBoot中整合MyBatis-Plus详细步骤(最新推荐)》本文详细介绍了如何在SpringBoot项目中整合MyBatis-Plus,包括整合步骤、基本CRUD操作、分页查询、批... 目录一、整合步骤1. 创建 Spring Boot 项目2. 配置项目依赖3. 配置数据源4. 创建实体类

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

SpringBoot整合InfluxDB的详细过程

《SpringBoot整合InfluxDB的详细过程》InfluxDB是一个开源的时间序列数据库,由Go语言编写,适用于存储和查询按时间顺序产生的数据,它具有高效的数据存储和查询机制,支持高并发写入和... 目录一、简单介绍InfluxDB是什么?1、主要特点2、应用场景二、使用步骤1、集成原生的Influ

SpringBoot实现websocket服务端及客户端的详细过程

《SpringBoot实现websocket服务端及客户端的详细过程》文章介绍了WebSocket通信过程、服务端和客户端的实现,以及可能遇到的问题及解决方案,感兴趣的朋友一起看看吧... 目录一、WebSocket通信过程二、服务端实现1.pom文件添加依赖2.启用Springboot对WebSocket