KMP算法的改进

KMP算法已经在极大程度上提高了子符串的匹配效率,但是仍然有改进的余地。

1. 引入的情景

下面我们就其中的一种情况进行分析:

  • 主串T为"aaaabcde…"
  • 子串S为"aaaade"

那么容易求得子串的next[]={0,1,2,3,4}

下标 1 2 3 4 5
子串 a a a a d
next 0 1 2 3 4

当使用KMP算法进行匹配时,

  • 由于T[5]!=S[5], 因此子串指针回溯,
  • 子串回溯后变为T[5]与S[4]的关系,依然不等, 子串继续回溯
  • 子串回溯后变为T[5]与S[3]的关系,依然不等,子串继续回溯
  • 子串回溯后变为T[5]与S[2]的关系,依然不等, 子串继续回溯
  • 子串回溯后变为T[5]与S[1]的关系,依然不等,子串继续回溯
  • 由于子串指针的值为0(j=0),主串和子串的指针同时向前移动一个位置,变为T[6]与S[1]的关系
  • … …

效果图如下:

实际上我们可以看出,S[1]=S[2]=S[3]=S[4], 既然S[4]!=T[5], 那么前面的几个根本无需比较。因此KMP 算法可进一步优化的地方便在于此。

2. 对KMP算法不足的说明

之所以出现上述问题,个人分析,原因在于:KMP的next数组只分析了当前字符之前的字符串的相似度,而没有把当前字符考虑进去, 从而导致上述没有意义的比较操作

那么如何才能把当前字符也考虑进去呢?

基本原理就是,在需要子串指针回溯时,进行当前位置元素与回溯之后位置元素比较,如果相等,那么就没有必要再进行比较了,子串的指针继续回溯。如此往复

因此,改进的KMP算法又添加了一个数组nextval, 它是在next基础之上计算出来的。

n

e

x

t

v

a

l

[

i

]

{

n

e

x

t

[

i

]

,

i

f

S

[

i

]

!

=

S

[

n

e

x

t

[

i

]

]

n

e

x

t

v

a

l

[

n

e

x

t

[

i

]

]

,

i

f

S

[

i

]

=

=

S

[

n

e

x

t

[

i

]

]

nextval[i]\begin{cases}next[i], &if\ S\ [i\ ]\ != \ S\ [ next\ [i\ ] \ ] \\nextval[next[i]], &if\ S\ [i\ ]\ == \ S\ [ next\ [i\ ] \ ] \\\end{cases}

nextval[i]{next[i],nextval[next[i]],​if S [i ] != S [next [i ] ]if S [i ] == S [next [i ] ]​

3. 改进KMP算法实现

/*************************************************************************
> File Name: kmp_pro.c
> Author: Toney Sun
> Mail: vip_13031075266@163.com
> Created Time: 2020年06月27日 星期六 21时07分12秒
************************************************************************/ #include<stdio.h>
#include<string.h>
#include<stdlib.h> int getNextVal(char *str, int nextval[])
{
int i = 0;
int j = -1; if(!str || !nextval){
printf("Parameters can't be NULL or can't be zero\n");
return -1;
} nextval[0] = -1;
printf("%2.2d ", nextval[0]);
while(i < strlen(str)-1){
if(j == -1 || str[i] == str[j]){
i++;
j++;
/*****************************************/
if(str[i]!=str[j]){
nextval[i]=j;
}else{
nextval[i]=nextval[j];
}
/*****************************************/
printf("%2.2d ", nextval[i]);
}else{
j = nextval[j];
}
}
printf("\n");
return 0;
} int kmp_pro(char *Str, char *match)
{
int i=0,j=0; int nextval[100] = {0}; int ret =getNextVal(match, nextval);
if(ret != 0){
printf("Get nextval error\n");
return -1;
}
while(i<(int)strlen(Str) && j<(int)strlen(match)){
if(j == -1 || Str[i] == match[j]){
i++;
j++;
}else{
j = nextval[j];
}
}
if(j == strlen(match)){
return i - j;
}else{
return -1;
}
} void main(int argc, char *argv[])
{
char *str="ababaaaaba";
char *match="aba"; int index = kmp_pro(str, match);
printf("-------index=%d------\n",index); match="aaa"; index = kmp_pro(str, match);
printf("-------index=%d------\n",index); match="aab"; index = kmp_pro(str, match);
printf("-------index=%d------\n",index); }

KMP算法的改进的更多相关文章

  1. 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现

    1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...

  2. KMP算法(改进的模式匹配算法)——next函数

    KMP算法简介 KMP算法是在基础的模式匹配算法的基础上进行改进得到的算法,改进之处在于:每当匹配过程中出现相比较的字符不相等时,不需要回退主串的字符位置指针,而是利用已经得到的部分匹配结果将模式串向 ...

  3. 字符串匹配(BF算法和KMP算法及改进KMP算法)

    #include <stdio.h> #include <string.h> #include <stdlib.h> #include<cstring> ...

  4. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

  5. 第4章学习小结_串(BF&KMP算法)、数组(三元组)

    这一章学习之后,我想对串这个部分写一下我的总结体会. 串也有顺序和链式两种存储结构,但大多采用顺序存储结构比较方便.字符串定义可以用字符数组比如:char c[10];也可以用C++中定义一个字符串s ...

  6. 算法 kmp算法

    kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...

  7. 字符串匹配的 KMP算法

    一般字符串匹配过程 KMP算法是字符串匹配算法的一种改进版,一般的字符串匹配算法是:从主串(目标字符串)和模式串(待匹配字符串)的第一个字符开始比较,如果相等则继续匹配下一个字符, 如果不相等则从主串 ...

  8. 关于《数据结构》课本KMP算法的理解

    数据结构课上讲的KMP算法和我在ACM中学习的KMP算法是有区别的,这里我对课本上的KMP算法给出我的一些想法. 原理和之前的KMP是一样的https://www.cnblogs.com/wkfvaw ...

  9. (原创)白话KMP算法详解

    引子:BF暴力算法 KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ...

随机推荐

  1. Spring Cloud分区发布实践(6)--灰度服务-根据Header选择实例区域

    此文是一个完整的例子, 包含可运行起来的源码. 此例子包含以下部分: 网关层实现自定义LoadBalancer, 根据Header选取实例 服务中的Feign使用拦截器, 读取Header Feign ...

  2. python3中的希尔排序

    def shell_sort(alist): n = len(alist) # 初始步长 gap = round(n / 2) while gap > 0: # 按步长进行插入排序 for i ...

  3. WinUI 3学习笔记(2)—— 用ListView来展示集合

    在WPF的时代,我们多是使用ListBox和ListView来展示,纵向滚动条显示的集合数据.这两个控件的默认样式,以及对触控的支持,已完全落后于时代.他们两个分别长这样,和Win10及Win11的风 ...

  4. i春秋“百度杯”CTF比赛 十月场-Vld(单引号逃逸+报错注入)

    题目源代码给出了提示index.php.txt,打开拿到了一段看不太懂得东西. 图片标注的有flag1,flag2,flag3,同时还有三段字符,然后还出现了_GET,脑洞一一点想到访问 ?flag1 ...

  5. C++ //深拷贝与浅拷贝 //浅拷贝 : 简单的赋值拷贝操作 //深拷贝: 在堆区重新申请空间 进行拷贝操作

    1 //深拷贝与浅拷贝 2 3 //浅拷贝 : 简单的赋值拷贝操作 4 //深拷贝: 在堆区重新申请空间 进行拷贝操作 5 6 7 #include <iostream> 8 using ...

  6. 关于Servlet技术

    1.Servlet 技术           a)什么是 Servlet                     1.Servlet 是 JavaEE 规范之一.规范就是接口              ...

  7. 十分钟带你了解CANN应用开发全流程

    摘要:CANN作为昇腾AI处理器的发动机,支持业界多种主流的AI框架,包括MindSpore.TensorFlow.Pytorch.Caffe等,并提供1200多个基础算子. 2021年7月8日,第四 ...

  8. 【Mongodb】数据库备份与还原

    Mongodb 备份与还原 Mongodb 备份与还原 文件快照 快照备份 快照直接还原 从压缩文件还原 复制文件 备份文件 从文件还原 mongodump mongodump备份 mongodump ...

  9. 【笔记】初探KNN算法(1)

    KNN算法(1) 全称是K Nearest Neighbors k近邻算法: 思想简单 需要的数学知识很少 效果不错 可以解释机器学习算法使用过程中的很多细节问题 更加完整的刻画机器学习应用的流程 其 ...

  10. JavaWeb——CSS总结

    CSS 记得大一下学期那会参加基地后就开始跟师兄师姐接触前端了,利用业余时间在站看各种视频.由于初次认知并且时间也能不固定集中,也存在跳跃式学习等等原因,这就导致了好多知识点要么漏掉要么没记全,只能懂 ...