在传统字符串匹配中我们求得字符串p出现在字符串s中的位置。我们把字符串s称为主串,字符串p称为模式串。

KMP算法的原理简单来说就是匹配的时候不回溯主串的指针i,而只回溯模式串指针j ,即匹配过程中,不移动主串,指移动模式串来达到"尽可能向右滑动最大的距离"。

s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s a c a b a a b a a b c a c a a b c
模式串p a b a a b c

图1.

假如模式串p中的c与s[11] 失配了,那么再传统匹配算法中,是拿s[7]和p[0] (a)去匹配,而在KMP匹配中是那s[11]和p[2] (a)中去匹配。因为在这次失配中可知,主串s中6~10的值就是abaab,再拿p[0]和s[7] 匹配必定失配,这次比较就显得多余。那么我们怎么知道失配的时候,模式串要向右移多少个单位呢?

假设图1此时主串要正在匹配的位置是 i =11 ,而 与 p[j]=='c',即j==5产生了失配,那么j指针要回溯到 某个k,假如=2值时要进行下一步匹配 ,那么k值必须满足两个关系式

由图一可知   p[3]p[4]=s[9]s[10],

由图二可知   p[0]p[1]=s[9]s[10]

s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s a c a b a a b a a b c a c a a b c
模式串p a b a

图2.

换成通用表达式就是

用逻辑意义上来解释公式3:就是当在模式串匹配第j个要回溯到k时此时j和k满足 前缀k个值和后缀k个值要相同。满足这条件的最大k值即为将要回溯的位置,假如用next数组表示模式串要回溯的位置其中 next[j]=k。

所以实际上,模式串中的next[j]的值与主串s是无关的。

假设next[j]=k即求next[j+1]

如果此时P[j] = P[k]  那么next[j+1]=k+1 即 next[j+1]= next[j] +1

如果此时 P[j] != P[k] ,那么就要移动next[k]个字符进行比较,达到s[i] = p[k],前缀与后缀对齐的目的。相等则next[j+1]=next[k]+1,不相等则迭代 k=next[k]重新移动比较,例如结合图3和图4,next[5]=2,求next[6]?

因为next[5]=2,所以比较出P[5] !=P[2],前缀无法对齐后缀就继续向右移(回溯),

因为next[2]=0,所以比较出P[5] !=p[0],

因为next[0]=-1接下来比对P[5]和P[-1] 因为next[0] = -1;

当不存在可回溯的k时next[j+1] = -1 ;

在存在一个可回溯的位置0<k'<k<j 那么

while(k'>0 && k'< k ){if(k' = -1){next[j+1] = 0;
}if(p[k'] != p[k]){k= next[k]}else{next[j+1] = next[k] +1
}
}
s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s a c a b a a b a a b c a c a a b c
模式串p a b a a b c a

图3

s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s a c a b a a b a a b c a c a a b c
模式串p a b a a b c a c

图4.

.

s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s a c a b a a b a a b c a c a a b c
模式串p a b a a b c a c

图5.

.所以字符串abaabcac的next值为 next [] = {-1,0,0,1,1,2,0,1};

改进的next ,

例如字符串 aaaab的next []={-1,0,1,2,3};

s[num] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
主串s
模式串p a a a a b

KMP算法中当s[9] 和p[3]  (b)比较失配发生回溯时,接下来s[9] 会和p[2]比较,此时这个比较是多余的必定会再次失配 。把多余的比较剔除掉就是改进的next。

如果回溯的值与原值相等即,  P[j] = P[k] 时直接 另 P[j] = P[next[k]];

hpp:

//
// Created by hu on 2020/8/5.
//#ifndef SMARTDONGLIB_SSTRING_H
#define SMARTDONGLIB_SSTRING_H
#include  <string>
#include <vector>namespace SmartDongLib {class SString {public:SString(){ str_="";}explicit SString(std::string str): str_(std::move(str)){}SString(const  SString& str){ str_=str.str_;}int length(){return str_.length();}SString copy(){return *this;};bool isEmpty(){return str_.empty();}void clear(){str_=""; }SString concat(const SString& str2){ SString  ret(str_ + str2.str_); return ret;}SString subString(int pos, int len){SString ret (str_.substr(pos, len)); return ret;}SString subString(int pos=0){SString ret (str_.substr(pos)); return ret;}int index( const SString& , int pos =0);int index_KMP(SString& str2, int pos=0);SString replace(SString src, const SString& target);void strinsert(int pos,const SString& T){str_.insert(pos, T.str_);}void strdelete(int pos,int len){str_.erase(pos,len);}SString operator+(std::string str1){ return SString(str_ + std::move(str1));}SString operator+=(std::string str1){ return SString(str_ + std::move(str1));}bool operator==(const std::string& str1){return str_==str1;}std::string get(){return str_;}void getnext(int next[]);private:std::string  str_;};
}#endif //SMARTDONGLIB_SSTRING_H

cpp  :

//
// Created by hu on 2020/8/5.
//#include "sdstructure/linearlist/SString.h"
namespace SmartDongLib {inline int SString::index(const SString& str2,  int pos ) {int iptr = pos , jptr = 0;while (iptr < str_.length() && jptr<str2.str_.length()){if (str_[iptr] == str2.str_[jptr]){//相等则比较下一位iptr++ ; jptr++;} else{//不相等则回溯,模式串指针从0 开始 i 回溯到原先的起始值+1 , 现值i'与原先的起始值i 满足 i'-i=j'-j其中j=0iptr = iptr - jptr+1;jptr = 0;}}if (jptr >=str2.str_.length()){return iptr - jptr;}return -1;}/*** <p> 1 . 求next数组,有了next数组后一个一个匹配,如果失配让 j = next[j];* @param substr* @param pos* @return*/inline int SString::index_KMP(SString& substr, int pos) {int i=pos, j=0;int next[substr.str_.length()];substr.getnext(next);int thisLen=length(),sublen=substr.length();while ( i < thisLen && j < sublen){if (j==-1 || str_[i] == substr.str_[j]){i++;j++;} else{j=next[j];}}if (j >= sublen){int ret =i-sublen;return ret;}return -1;}inline SString SString::replace(SString src, const SString& target) {if (src.str_.empty()){return *this;}int index=0;while ( index != -1) {index = index_KMP(src);if(index != -1) {str_.erase(index,  src.str_.length());str_.insert(index, target.str_);}}return *this;}/*** <p>原理: 当求next的第j个元素时,看  j-1 个元素开始和第0个元素比对,k不断增加取最大值满足  0<k<j* 从后往前数k个即第 j-k+1...j-1元素与 0...k-1* 如  abaabcac    当(a)j=0 next[0]=0 ; (b)j =1 ,next[1]=1,;(a) j=2时,k=1,第1个元素和第0个元素比对即a和b比不对就是1*  当(a)j=3,k=1,第2个元素和第0个元素 比a和a匹配上了 那就是next[3]=2;* @param substr* @return*/inline void SString::getnext(int next[]) {const int len =str_.length();
//        next.resize(len,-1);int i = 0,j=-1;next[0]=-1;while (i<len){if (j==-1 ||str_[i] == str_[j]){++i;++j;next[i]=j;} else{j=next[j];}}//return next;}
}

example:

//
// Created by hu on 2020/8/6.
//#include <iostream>
#include "sdstructure/linearlist/SString.cpp"
using namespace std;
using namespace SmartDongLib;
int main(){SString mainstr("acabaabaabcacaabc");SString substr("abaabcac");//-1   0   -1   1   0   2   -1   1SString target("ijn");int next[substr.length()];substr.getnext(next);for (int i :next){cout<<i<<"   ";}int index=mainstr.index_KMP(substr);int index2=mainstr.index(substr);cout<<endl<<index;cout<<endl<<index2;mainstr.replace(substr,target);cout<<endl<<mainstr.get();
}

C++ : KMP 字符串匹配算法相关推荐

  1. KMP字符串匹配算法理解(转)

    一.引言 主串(被扫描的串):S='s0s1...sn-1',i 为主串下标指针,指示每回合匹配过程中主串的当前被比较字符: 模式串(需要在主串中寻找的串):P='p0p1...pm-1',j 为模式 ...

  2. 字符串匹配KMP算法设计C语言,KMP字符串匹配算法笔记

    网上有很多解释KMP算法的文章,A_B_C_ABC的这篇很详细,反复看了好几遍,总算理解了个大概,但是总觉得没那么爽快.其实,一种算法各人有各人的理解方法,找到适合自己理解的才容易记住.下面是我对这个 ...

  3. Java实现算法导论中KMP字符串匹配算法

    "前缀"和"后缀". "前缀"指除了最后一个字符以外,一个字符串的全部头部组合:"后缀"指除了第一个字符以外,一个字符串 ...

  4. 每周一算法之六——KMP字符串匹配算法

    KMP是一种著名的字符串模式匹配算法,它的名称来自三个发明人的名字.这个算法的一个特点就是,在匹配时,主串的指针不用回溯,整个匹配过程中,只需要对主串扫描一遍就可以了.因此适合对大字符串进行匹配. 搜 ...

  5. 【KMP】KMP 字符串匹配算法

    文章目录 1.概述 2.暴力匹配算法 3.KMP算法 3.1 案例 3.2 部分匹配表 3.3 匹配 M.参考 本文为博主九师兄(QQ:541711153 欢迎来探讨技术)原创文章,未经允许博主不允许 ...

  6. 字符串匹配算法(KMP)

    文章目录 1. KMP由来 2. KMP算法基本原理 3. 代码 4. Leetcode 28. 实现 strStr() 1. KMP由来 上一节说的BM算法是最高效.最常用的字符串匹配算法. 最知名 ...

  7. 字符串匹配算法之KMP

    目录 需求 基础知识 逻辑解析 源码实现 需求 先简单描述溪源曾经遇到的需求: 需求一:项目结果文件中实验结论可能会存在未知类型.转换错误.空指针.超过索引长度等等.这里是类比需求,用日常开发中常出现 ...

  8. 数据结构与算法分析(十六)--- 如何设计更高效的字符串匹配算法?(BF + RK + KMP + BMH)

    文章目录 一.Brute Force 匹配算法 二.Rabin–Karp 匹配算法 三.Knuth–Morris–Pratt 匹配算法 四.Boyer-Moore-Horspool 匹配算法 五.字符 ...

  9. C++实现KMP(Knuth-Morris-Pratt)字符串匹配算法

    #include"iostream"using namespace std;// 暴力匹配算法 bool string_match(char *mains,unsigned int ...

最新文章

  1. Android之子菜单的创建
  2. python属性和方法的区别_Python中几种属性访问的区别
  3. LeetCode 1061. 按字典序排列最小的等效字符串(并查集)
  4. ubuntu14.04下 安装matlabR2015b遇到的一些问题及其解决方法
  5. JS 实现 Tab标签切换功能
  6. 三维点云学习(3)6- 实现K-Means
  7. XP系统优化超简单实用版
  8. 【python】短信验证之腾讯云短信验证详细步骤
  9. 《SEM长尾搜索营销策略解密》一一2.4 长尾的主动与被动
  10. 转录组测序day 1 基础知识
  11. iOS 判断机型是否为iPhone Xs
  12. 网站服务器登录很慢,网站打开速度慢如何解决?有何技巧?
  13. Apriori关联分析算法 -尿布与啤酒的故事
  14. 算法.动态规划 导航/数塔取数字问题
  15. 内网渗透(五十)之域控安全和跨域攻击-使用其他工具导出域账号和散列值
  16. Word学习笔记分享
  17. 14届蓝桥杯Python总结
  18. 迅雷播放插件下载的在线字幕位置
  19. 图像超分算法SRLUT: Practical Single-Image Super-Resolution Using Look-Up Table图像超分辨率重建
  20. 手机相机里面的m_让手机具备M档 WP专业拍照软件ProShot

热门文章

  1. Linux 永久修改主机名hostname
  2. openssl加密http网站过程1
  3. Bootstrap3系列:下拉菜单
  4. 简单讨论火车票系统后面的架构设计
  5. .NET新手系列(五)
  6. 【Leetcode】EASY题解....ing python
  7. 如何通过递归找父节点或子节点详解
  8. 【收藏】win10将wsl升级到wsl2
  9. Linux time ls命令:用户态内核态分别占用多长时间
  10. Linux vim光标快速移动指定行数G