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. BUU八月份水题记录

    目录 [BJDCTF 2nd]fake google(SSTI) [BJDCTF2020]Easy MD5(md5注入) [ZJCTF 2019]NiZhuanSiWei(反序列化) [BJDCTF ...

  2. 用 Java 实现常见的 8 种内部排序算法

    一.插入类排序 插入类排序就是在一个有序的序列中,插入一个新的关键字.从而达到新的有序序列.插入排序一般有直接插入排序.折半插入排序和希尔排序. 1. 插入排序 1.1 直接插入排序 /** * 直接 ...

  3. SaToken学习笔记-03

    SaToken学习笔记-03 如果排版有问题,请点击:传送门 核心思想 所谓权限验证,验证的核心就是一个账号是否拥有一个权限码 有,就让你通过.没有?那么禁止访问! 再往底了说,就是每个账号都会拥有一 ...

  4. .net core 响应的json数据驼峰显示问题。

    在.net core webapi中,默认响应的json数据是以驼峰显示的,即首字母小写的方式.如果让其正常显示,只需要在全局配置即可.代码如下图: 配置之后,响应数据就不会再以驼峰的形式展示了.而是 ...

  5. Java-SpringBoot注解方式实现AOP

    AOP基本总结 连接点(JoinPoint): 连接点是程序运行的某个阶段点,如方法调用.异常抛出等 切入点(Pointcut): 切入点是JoinPoint的集合 是程序中需要注入Advice的位置 ...

  6. 跟我一起写 Makefile(六)

    书写命令 ---- 每条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的.在命令行 ...

  7. Golang语言系列-07-函数

    函数 函数的基本概念 package main import ( "fmt" ) // 函数 // 函数存在的意义:函数能够让代码结构更加清晰,更简洁,能够让代码复用 // 函数是 ...

  8. MySQL-03-基础管理

    用户和权限管理 用户管理 作用:登录,管理数据库逻辑对象 定义:用户名@'白名单' 白名单支持的方式 wordpress@'10.0.0.%' wordpress@'%' wordpress@'10. ...

  9. 【XSS-labs】level 16-20

    Level 16 查看源码:发现 空格 / 和script都被转义了. 用img标签的onerror事件(在加载外部文档或图片出错后触发),空格用%0a绕过,  payload如下: <img% ...

  10. 题解 UVA10225 Discrete Logging

    本题是一道 \(BSGS\) 裸题,用于求解高次同余方程,形如 \(a^x\equiv b(\mod p)\),其中 \(a\),\(p\) 互质(不互质还有 \(EXBSGS\)). 建议多使用 \ ...