博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法导论 KMP字符串匹配
阅读量:4088 次
发布时间:2019-05-25

本文共 2766 字,大约阅读时间需要 9 分钟。

KMP字符串匹配

1. KMP字符串匹配的原理
Knuth-Morris-Pratt算法(简称KMP),是一种非常高效的字符串匹配。设n为文本的长度,m为待查找文本模板的长度,则预处理时间需要O(m),匹配时间需要O(n)。
1.预处理阶段。KMP字符串匹配的原理就是为待查找的字符串模板创建一个前缀函数,该前缀函数得到对于模板每一个子字符串(1~i),若有相同的长度的前缀和相同的长度的后缀的字符串相同的话,返回前缀/后缀的最大长度。可能这个概念说的有点模糊,看一个例子:

例如ababc这个自字符串模板,前缀函数的值是这样计算的:

对于子字符串a,规定在只有一个字符串,该前缀函数返回长度0。
对于子字符串ab,由于任何相同长度的前缀和后缀都不相同,所以前缀函数返回长度0。
对于子字符串aba,由于前缀a和后缀a相同,并且无更长的前缀和后缀相同,故返回长度1。
对于子字符串abab,由于前缀ab和后缀ab相同,并且无更长的前缀和后缀相同,故返回长度2。
对于子字符串ababc,由于任何相同长度的前缀和后缀都不相同,并且无更长的前缀和后缀相同,故返回长度0。

2.查找阶段。遍历文本的每一个字符,

(1).若新扫描进来的字符和模板匹配,则继续扫描(扫描位置后移)。
(2).若新扫描进来的字符和模板不匹配(扫描位置暂时不动)。利用前缀函数在模板中找到一个前缀,从该前缀的后一个位置开始继续和文本匹配。(为什么可以从从该前缀的后一个位置开始?因为该前缀就是之前匹配成功的字符串的后缀,因此可以避免重复扫描已经匹配成功的字符)
不断循环如上两步即可,直到匹配成功的字符个数恰好为待匹配的字符串模板长度则为查找成功,或者遍历文本每一个字符都查找不到则为查找失败。

2. KMP字符串匹配实现(伪代码)

这里写图片描述

这里写图片描述

你可以看到计算前缀函数跟匹配函数非常相识,这是因为计算前缀函数其实是待查找的字符串模板跟自身匹配,而匹配函数是待查找的字符串模板跟查找文本匹配。

3. KMP字符串匹配实现(C++代码)

#pragma once#include 
class KMPMatcher{public: KMPMatcher(std::string pattern); std::string const& GetPattern() const; void SetPattern(std::string val); unsigned int Search(std::string str, unsigned int startPos = 1);private: std::string m_pattern; int* m_prefixValue;};
#include "KMPMatcher.h"#include 
std::string const& KMPMatcher::GetPattern() const{ return m_pattern;}void KMPMatcher::SetPattern(std::string val){ m_pattern = val; //计算前缀函数 std::string pattern = val; //这两个变量没有必要,但是可以增加阅读性 std::string text = val; //这两个变量没有必要,但是可以增加阅读性 int currentMatch = 0; m_prefixValue = new int[val.length()]; m_prefixValue[0] = 0; for (int i = 2; i != text.length()+1; i++) { while (currentMatch > 0 && text[i-1] != pattern[currentMatch]) { currentMatch = m_prefixValue[currentMatch-1]; } if (text[i-1] == pattern[currentMatch]) { ++currentMatch; } m_prefixValue[i-1] = currentMatch; }}KMPMatcher::KMPMatcher(std::string pattern){ SetPattern(pattern);}unsigned int KMPMatcher::Search(std::string str, unsigned int startPos /*= 1*/){ std::string pattern = m_pattern; std::string text = str; int currentMatch = 0; for (int i = startPos; i != text.length()+1; i++) { while (currentMatch > 0 && text[i-1] != pattern[currentMatch]) { currentMatch = m_prefixValue[currentMatch-1]; } if (text[i-1] == pattern[currentMatch]) { ++currentMatch; } if (currentMatch == pattern.length()) { return static_cast
(i - pattern.length() + 1); } } return 0; //查找不到}
//main.cpp#include "KMPMatcher.h"#include 
using namespace std;int main(){ KMPMatcher testKMP("ababa"); cout << "查找结果:" << testKMP.Search("abaababa") << endl; return 0;}

4. 程序运行结果

查找结果:4

你可能感兴趣的文章
ACfly之所以不怕炸机因为它觉得某个传感器数据不安全就立马不用了
查看>>
我发觉,不管是弄ROS OPENCV T265二次开发 SDK开发 caffe PX4 都是用的C++
查看>>
ROS的安装(包含文字和视频教程,我的ROS安装教程以这篇为准)
查看>>
国内有个码云,gitee
查看>>
原来我之前一直用的APM固件....现在很多东西明白了。
查看>>
realsense-ros里里程计相关代码
查看>>
似乎写个ROS功能包并不难,你会订阅话题发布话题,加点逻辑处理,就可以写一些基础的ROS功能包了。
查看>>
if __name__ == ‘__main__‘:就是Python里的main函数,脚本从这里开始执行,如果没有main函数则从上到下顺序执行。
查看>>
PX4官方用户和开发手册的首页面是会给你选择英文和中文的
查看>>
网络协议栈我是不是可以这么理解,就是把你要发送的数据自动处理成TCPIP格式的消息发出去,这种底层的转换不需要你弄了。
查看>>
除了LwIP还有uIP
查看>>
《跟工程师学嵌入式开发》这本书最后的终极项目我反而觉得有说头
查看>>
博士的申请考核制
查看>>
那些硬件的初始化函数主要是在做些上什么?
查看>>
MAVLink学习之路05_MAVLink应用编程接口分析(也有讲STM32下的收发函数)
查看>>
找到了中文版的mavlink手册
查看>>
浅谈飞控开发的仿真功能
查看>>
我觉得在室内弄无人机开发装个防撞机架还是很有必要的,TBUS就做得很好。
查看>>
serial也是见到很多次了,似乎它就是一种串行通信协议
查看>>
TBUS的一些信息
查看>>