KMP算法的改进
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算法的改进的更多相关文章
- 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现
1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...
- KMP算法(改进的模式匹配算法)——next函数
KMP算法简介 KMP算法是在基础的模式匹配算法的基础上进行改进得到的算法,改进之处在于:每当匹配过程中出现相比较的字符不相等时,不需要回退主串的字符位置指针,而是利用已经得到的部分匹配结果将模式串向 ...
- 字符串匹配(BF算法和KMP算法及改进KMP算法)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include<cstring> ...
- 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案
之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...
- 第4章学习小结_串(BF&KMP算法)、数组(三元组)
这一章学习之后,我想对串这个部分写一下我的总结体会. 串也有顺序和链式两种存储结构,但大多采用顺序存储结构比较方便.字符串定义可以用字符数组比如:char c[10];也可以用C++中定义一个字符串s ...
- 算法 kmp算法
kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...
- 字符串匹配的 KMP算法
一般字符串匹配过程 KMP算法是字符串匹配算法的一种改进版,一般的字符串匹配算法是:从主串(目标字符串)和模式串(待匹配字符串)的第一个字符开始比较,如果相等则继续匹配下一个字符, 如果不相等则从主串 ...
- 关于《数据结构》课本KMP算法的理解
数据结构课上讲的KMP算法和我在ACM中学习的KMP算法是有区别的,这里我对课本上的KMP算法给出我的一些想法. 原理和之前的KMP是一样的https://www.cnblogs.com/wkfvaw ...
- (原创)白话KMP算法详解
引子:BF暴力算法 KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ...
随机推荐
- (11)MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)
1.概述 前面章节之所以介绍那么多锁的知识点和示例,其实最终目的就是为了排查与解决死锁的问题,下面我们把之前学过锁知识重温与补充一遍,然后再通过例子演示下如果排查与解决死锁. 2.前期准备 ●数据库事 ...
- Java数组06——冒泡排序
冒泡排序 例子: package array; import java.util.Arrays; public class ArrayDemon08 { public static ...
- Cell Reports | 上海瑞金医院糜坚青等揭示组蛋白酰化/乙酰化修饰比率调控BRD4基因组分布
景杰生物 | 报道 组蛋白翻译后修饰,被认为构成一类超越基因序列的"组蛋白密码",控制着遗传信息的组织层次及其在染色质层面的解读.组蛋白赖氨酸乙酰化是研究最早的一类组蛋白修饰, ...
- Git8.3k星,十万字Android主流开源框架源码解析,必须盘
为什么读源码 很多人一定和我一样的感受:源码在工作中有用吗?用处大吗?很长一段时间内我也有这样的疑问,认为哪些有事没事扯源码的人就是在装,只是为了提高他们的逼格而已. 那为什么我还要读源码呢?一刚开始 ...
- MapReduce框架原理-MapTask和ReduceTask工作机制
MapTask工作机制 并行度决定机制 1)问题引出 maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度.那么,mapTask并行任务是否越多越好呢? 2)MapTa ...
- zookeeper的简介和相关命令操作
.personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...
- 结合scipy.linalg在Python中使用线性系统
摘要:将线性代数概念应用到实际问题中scipy.linalg 使用 Python 和 NumPy处理向量和矩阵 使用线性系统模拟实际问题 使用求解线性系统 scipy.linalg 本文分享自华为云社 ...
- S3C2440—11.und异常
文章目录 1 未定义指令 2 中断向量表 3 设置一个未定义指令 4 调用C函数 5 UND异常处理程序 6 汇编源码 7 注意点 lr与pc 保存现场 中断向量表的跳转 程序执行顺序 问题 1 未定 ...
- 数据结构与算法-排序(九)基数排序(Radix Sort)
摘要 基数排序是进行整数序列的排序,它是将整数从个位开始,直到最大数的最后一位截止,每一个进位(比如个位.十位.百位)的数进行排序比较. 每个进位做的排序比较是用计数排序的方式处理,所以基数排序离不开 ...
- .Net Core 踩坑记录--程序独立发布 无法运行
背景 创建.net Core3.1 的Console程序 点击发布 选择独立部署模式 目标电脑 Win10 x64 未安装任何.Net SDK 现象 发布的程序 点击运行没有反应 或是直接闪退 解决 ...