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算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ... 
随机推荐
- MapReduce框架原理-MapTask和ReduceTask工作机制
			MapTask工作机制 并行度决定机制 1)问题引出 maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度.那么,mapTask并行任务是否越多越好呢? 2)MapTa ... 
- 代码中如何优化过多的if..else
			针对代码中,过多的 if ... else ..,如何优化减少if else呢?(非常重要的优化技巧) 缺点:过多的if else 导致阅读不方便,逻辑过于复杂,代码多长. 解决方法:可以采用多个方 ... 
- Java-Dubbo学习及整合SpringBoot
			Dubbo架构 Dubbo是Java的RPC框架,具有三大核心功能:面向接口的远程方法调用,智能容错和负载均衡,以及服务的自动注册和发现 Dubbo架构图: 节点角色说明: 节点 说明 Provide ... 
- Linux 硬盘与硬件管理
			硬件以文件系统(Filesystem)角度来看 文件系统:一个可被挂载的数据称为文件系统,每个操作系统可以使用的文件系统并不一样,windows98是FAT或者FAT16文件系统,而windows20 ... 
- Servelt&&JSP进阶
			Servlet与JSP进阶 来自mkw的视频课程的总结 1.前言 内容包括 掌握Java Web核心特性,Servlet核心对象以及JSP九大内置对象.主要有以下的内容: 请求结构 && ... 
- websocket在慕课网中的应用
			网上资料都是介绍概念,我们来看看实际网站怎么使用websocket的吧.限于自身水平解读并不深入,慕课网上的websocket某些字段不知何用. 是什么 是一种应用层协议,有html5而推出,是一种全 ... 
- Docker创建Docker-Registry-私服
			docker-compose.yml version: '3.1' services: registry: image: registry restart: always container_name ... 
- Failed to set locale, defaulting to C.UTF-8
			CentOS 8中执行命令,出现报错:Failed to set locale, defaulting to C.UTF-8 报错原因: 1.没有安装相应的语言包. 2.没有设置正确的语言环境. 解决 ... 
- COM笔记-引用计数
			参考网站:https://www.cnblogs.com/fangyukuan/archive/2010/06/06/1752621.html com组件将维护一个称作是引用计数的数值.当客户从组件取 ... 
- servlet防止表单重复提交
			日常开发中,防表单重复提交是一项必须的工作 我们可以利用javascript防止表单重复提交,但是利用javascript防止表单重复提交会出现一个新的问题 因为某些用户可能会绕过script代码直接 ... 
