KMP 算法简单解释
 讲KMP算法,离不开BF,实际上,KMP就是BF升级版,主要流程和BF一样
 不同是在匹配失败时能利用子串的特征减少回溯,利用根据子串特征生成的Next数组来减少
<( ̄︶ ̄)↗[GO!]
!!!所有数组下标都是从0开始
1. 先看看BF算法(暴力破解)
int Brute_force_1(const char *S, const char *T)
{
	if (!S || !T)
		return -1;
	int lenS = strlen(S);
	int lenT = strlen(T);
	int i = 0;				//主串下标索引
	int j = 0;				//子串下标索引
	while(i < lenS && j < lenT)
	{
		if (S[i] == T[j])	//如果相等一直继续往下匹配
            ++i,++j;
		else				//不相等i和j开始回溯
		{
			i = i-j+1;
			j = 0;
		}
	}
	if (j == lenT)
		return i - j;
	return -1;
}
 BF算法有几种不同实现,但最终思想都是一样的,以下就是另一个BF实现
int Brute_force_2(const char *S, const char *T)
{
	if (!S || !T)
		return -1;
	int lenS = strlen(S);
	int lenT = strlen(T);
	for (int i = 0; i <= lenS - lenT; ++i)
	{
		int k = i, j = 0;
		while (k < lenS && j < lenT && S[k] == T[j])
		{
			++j;
			++k;
		}
		if (j == lenT)
			return i; //说明匹配到了
	}
	return -1;
}
 你完全可以根据自己的理解写出BF算法,但在这里,为了BF和KMP统一,我们还是采用第一种实现,即容易看出回溯操作的实现
2. Next[]数组
 事实上,书上的next数组生成算法是经过优化后的算法,比较难懂,但你完全可以按照自己的理解做一个
 注意:Next[]数组只是在KMP中字符串匹配失败时使用的
void GetNext(int Next[], char *str)
{
	assert(str!=NULL);
	int len = strlen(str);
	if(len>1)Next[0]=0;
//其实Next[0]等于0或者等于-1效果没什么影响,
//因为在KMP中不匹配时判断是不是第一个字符不匹配用用的是j==0;-----if (j==0||Next[j]==0),
	if(len>2)Next[1]=0;
//Next[]等于0时说明需要讲i回溯到子串头的下一个位置(i=i-j+1);
//此时j也回到子串头位置(j=0)
	for(int i=2;i<len;++i)
	{
		for(int j=i-1;j>0;--j)
		{
			if(!strncmp(&str[0],&str[i-j],j))
			{
				Next[i]=j;break;		//找到最大重复子子串(子串中的子串)
//Next[]为其他值则i不变,讲j回溯到Next[j]的位置(j=Next[j])
			}
			else Next[i]=0;
		}
	}
}
 这个时间复杂度要比书上的方法高很多,但好理解,真实的反映了Next数组的本质。
3. KMP
int KMP(const char *S, const char *T, const int *Next)
{
	if (!S || !T||!Next)
		return -1;
    int lenS = strlen(S);
	int lenT = strlen(T);
	int i = 0;				//主串下标索引
	int j = 0;				//子串下标索引
	while(i < lenS && j < lenT)
	{
		if (S[i] == T[j]) ++i,++j;	//若相等则继续匹配下一个字符
		else		//不相等则回溯
		{
            //(当j==0时,即第一个字符不匹配,和Next[j]==0时事实上与BF算法相同)
			if (j==0||Next[j]==0)
            {
				i = i-j+1;
				j = 0;
			}
			else j = Next[j];//主串i位置不变,讲子串下标索引挪到Next[j]的位置
		}
	}
	if (j == lenT)
		return i - j;
	return -1;
}
 这个回溯时的操作实际上是把两种情况合成一种,拆开后就是下面的,就是生成next数组那块三种情况
while (i < lenS && j < lenT)
{
	if (S[i] == T[j])
		++i, ++j;
	else
	{
		if (j == 0)
		{
			++i; //等价于i = i-0+1;j本身就等于0
		}
		else if (Next[j] == 0)
		{
			i = i - j + 1;
			j = 0;
		}
		else
		{
			j = Next[j];
		}
	}
}
扩展
 Next数组有进一步改进的可能,如果发生失配,失配点子串字符若与回溯到的字符相同,则再次匹配肯定失败,所以改进的Next数组进一步处理了这种情况,消除了回溯
void GetNext_pro(int Next[], const char *str)
{
	assert(str!=NULL);
	int len = strlen(str);
	if(len>1)Next[0]=-1;
//其实Next[0]等于0或者等于-1效果没什么影响,
//因为在KMP中不匹配时判断是不是第一个字符不匹配用用的是j==0;-----if (j==0||Next[j]==0),
	if(len>2)Next[1]=0;
//Next[]等于0时说明需要讲i回溯到子串头的下一个位置(i=i-j+1);
//此时j也回到子串头位置(j=0)
	for(int i=2;i<len;++i)
	{
		for(int j=i-1;j>0;--j)
		{
			if(!strncmp(&str[0],&str[i-j],j))
			{
				if(str[i]==str[j])
					Next[i]==Next[j];
				else
					Next[i]=j;
				break;		//找到最大重复子子串(子串中的子串)
//Next[]为其他值则i不变,讲j回溯到Next[j]的位置(j=Next[j])
			}
			else Next[i]=0;
		}
	}
}
测试代码
int KMP(const char *S, const char *T)
{
	if (!S || !T)
		return -1;
	int Next[MAXSIZE] = {0};
	GetNext(Next,T);
	print_arr(Next, strlen(T));
	GetNext_pro(Next,T);
	print_arr(Next, strlen(T));
    int lenS = strlen(S);
	int lenT = strlen(T);
	int i = 0;				//主串下标索引
	int j = 0;				//子串下标索引
	while(i < lenS && j < lenT)
	{
		if (S[i] == T[j])
			++i,++j;	//若相等则继续匹配下一个字符
		else		//不相等则回溯
		{
            //(当j==0时,即第一个字符不匹配,和Next[j]==0时事实上与BF算法相同)
			if (j==0||Next[j]==0)
            {
				i = i-j+1;
				j = 0;
			}
			else j = Next[j];//主串i位置不变,将子串下标索引挪到Next[j]的位置
		}
	}
	if (j == lenT)
		return i - j;
	return -1;
}
int main(void)
{
	char source[MAXSIZE] = "adcfabadcf";
	char target[MAXSIZE] = "abcabcabbac";
	printf("%d\n", Brute_force_1(source, target));
	printf("%d\n", Brute_force_2(source, target));
	printf("%d\n", KMP(source, target));
	getchar();
	return 0;
}
附上BF与KMP的比较,你会发现两者其实挺相似

总结
 其实核心就在于本文第一句话的理解。
 KMP在子串含有相同前后缀时,利用Next数组减少匹配失败时的回溯次数有优势,而改进的Next数组在此基础上若子串含有较多相同字符则更进一步减少回溯。
 所以KMP总之是利用子串的特征来削除回溯,如果子串并不具有这些特征,那就还没有BF好,因为KMP还需要额外的空间来存放Next数组
 书上的next数组的生成很难懂,加油理解中。。。(ง •_•)ง
KMP 算法简单解释的更多相关文章
- KMP算法具体解释(贴链接)
		---------------------------------------------------------------------------------------------------- ... 
- KMP算法具体解释(转)
		作者:July. 出处:http://blog.csdn.net/v_JULY_v/. 引记 此前一天,一位MS的朋友邀我一起去与他讨论高速排序,红黑树,字典树,B树.后缀树,包含KMP算法,只有在解 ... 
- KMP算法简单回顾
		前言 虽从事企业应用的设计与开发,闲暇之时,还是偶尔涉猎数学和算法的东西,本篇根据个人角度来写一点关于KMP串匹配的东西,一方面向伟人致敬,另一方面也是练练手,头脑风暴.我在自娱自乐,路过的朋友别太认 ... 
- KMP算法具体解释
		这几天学习kmp算法,解决字符串的匹配问题.開始的时候都是用到BF算法,(BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配 ... 
- 串的应用与kmp算法讲解--学习笔记
		串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ... 
- 字符串匹配KMP算法的C语言实现
		字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ... 
- 字符串匹配(KMP 算法 含代码)
		主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知 ... 
- (收藏)KMP算法的前缀next数组最通俗的解释
		我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度. 当然我们可以看到这个算法针对的是子串有对称属性, ... 
- KMP算法的next[]数组通俗解释
		原文:https://blog.csdn.net/yearn520/article/details/6729426 我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以 ... 
随机推荐
- 部署描述符web.xml
			部署描述符应用场景 需要传递初始参数给ServletContext 有多个过滤器,并要指定调用顺序 需要更改会话超时设置 要限制资源的访问,并配置用户身份验证方式 xsi:schemaLocation ... 
- 每天一个linux命令(15)-tail
			tail 命令从指定点开始将文件写到标准输出.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不断刷新, ... 
- Redis-输入输出缓冲区
			一.client list id:客户端连接的唯一标识,这个id是随着Redis的连接自增的,重启Redis后会重置为0addr:客户端连接的ip和端口fd:socket的文件描述符,与lsof命令结 ... 
- C++走向远洋——60(十四周阅读程序、STL中的简单容器和迭代器)
			*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ... 
- Java入门教程一(Java简介)
			什么是Java语言 Java 是由 Sun Microsystems 公司于 1995 年推出的一门面向对象程序设计语言.2010 年 Oracle 公司收购 Sun Microsystems,之后由 ... 
- .NET微服务从0到1:服务注册与发现(Consul)
			目录 Consul搭建 基于Docker搭建Consul 基于Windows搭建Consul ServiceA集成Consul做服务注册 Ocelot集成Consul做服务发现 更多参考 Consul ... 
- Win32 按钮嵌套收不到消息解决记录
			太长不看 SetWindowSubClass,然后 return DefSubclassProc(hWnd, uMsg, wParam, lParam);,不要有 WS_CHILD 这个 Style. ... 
- (数据科学学习手札79)基于geopandas的空间数据分析——深入浅出分层设色
			本文对应代码和数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 通过前面的文章,我们已经对geopanda ... 
- 论nw.js的坑~~~感觉我所有的前端能遇到的坑都踩了一遍
			先总结:nw.js 真特么的...难用...文档,我得先百度才能看的稍微明白点文档......!!!!!!我感觉我所有的前端能遇到的坑都踩了一遍,此文针对前后端分离项目,别的先不说 一.不需要在项目里 ... 
- SpiningUP 强化学习 中文文档
			2020 OpenAI 全面拥抱PyTorch, 全新版强化学习教程已发布. 全网第一个中文译本新鲜出炉:http://studyai.com/course/detail/ba8e572a 个人认为 ... 
