数据结构与算法基础(王卓)(16):KMP算法详解(代码实现)

news2025/3/1 11:39:44

 实现代码的过程中

具体细节、问题:

(1):关于写Get_next函数的标题:


现象:

PPT上写的是:

void get_next(SString T, int &next[])

然而并不能运行,而当我们去掉了引用符号(&)以后:

void get_next(SString T, int next[])

却可以运行,但是这里引用的符号就代表着把数据传回(给)主函数,所以最好不要省略

//&:返回所有我们算出的next[]


原因:

数组不能采用引用格式来传值

根本不存在“元素都是引用的数组”:

本身数组就是用他的首地址来传值的,其首地址代表一大串数组的信息和地址(位置)

而引用传值只是给变量取了一个别名来传值,自然不能无法整个数组的值

总得来说就是一个格式的问题


(2):关于Get_next函数中k的初值:

	int j = 0,//从头开始算起
		k = -1;
	next[0] = -1;//根据公式

一开始我们想令 k = 0; ,后面真的想去运行以后发现不可以:

根据公式和算法设计,即使是MAX[k]也必须要小于j


(3):关于KMP函数里,next数组赋初值 和 调用Get_next函数的语句的问题:

不同版本不同教材的不同写法:


 网课(PPT):

	int i = pos, j = 1;

没有给next数组赋初值

也没有调用Get_next函数

啥也没有,主打的就是一个陪伴

这样是肯定不行的:


书上:

	int next[MAXLEN];
	int i = pos, j = 1;
	Get_next(T, next);

给next数组赋初值

调用Get_next函数,但是里面写的是next而非next[]

结果:


把书上的改进为:

给next数组赋初值

调用Get_next函数,并且写next[]

	int next[MAXLEN];
	int i = pos, j = 1;
	Get_next(T, next[]);

结果也不行:

到这里,我们似乎已经山穷水尽,走投无路了

这个时候多和同学沟通交流就成了关键,于是我们又有了如下进展,这也是我们最终最重要的

问题(3)的收获:


(1):首先:

给next数组赋初值不能少毋庸置疑,没有可能说有那个变量能够不赋初值就直接进行运算操作的

所以PPT上的情况肯定是不行的(差评)


(2):对于书上写的这种情况:

如果我们不要这个Get_next函数的引用符号(不再采用引用传值)

采用实参形参传值,即将其定义的抬头改为:

void Get_next(SString T, int next[])

程序即可成功正确运行:(完整程序如下)这也正是我们

用next最终实现KMP算法的结果:

#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit

typedef int Status;
#define MAXLEN 255

struct SString
	//Sequence String
{
	char ch[MAXLEN + 1]; //存储串的一维数组
	int length; //串的当前长度长度
};

void Get_next(SString T, int next[])
//给你一个子串T,教你逐个算出每个位序对应的next[]
{
	int j = 0,//从头开始算起
		k = -1;
	next[0] = -1;//根据公式
	while (j <= T.length - 1)//因为位序从0(而非1)开始
	{
		if (k == -1 || T.ch[k] == T.ch[j])
		{
			j++;
			k++;
			next[j] = k;
		}
		else
			k = next[k];
	}
}

int Index_KMP(SString S, SString T, int pos)
{
	int next[MAXLEN];
	Get_next(T, next);
	int i = pos, j = 1;
	while (i <= S.length && j <= T.length)
	{
		if (S.ch[i] == T.ch[j])
		{
			++i; ++j;
		}//主串和子串依次匹配下一个字符
		else

			j = next[j];
	}
	if (j > T.length)
		return i - T.length; //匹配成功
	else
		return 0;
}

int main()
{

}

同样的,我们不采用引用,我们也还可以采用地址传值,将其定义Get_next的抬头改为:

void Get_next(SString T, int *next)

程序即可成功正确运行:(完整程序如下)

#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit

typedef int Status;
#define MAXLEN 255

struct SString
	//Sequence String
{
	char ch[MAXLEN + 1]; //存储串的一维数组
	int length; //串的当前长度长度
};

void Get_next(SString T, int *next)
//给你一个子串T,教你逐个算出每个位序对应的next[]
{
	int j = 0,//从头开始算起
		k = -1;
	next[0] = -1;//根据公式
	while (j <= T.length - 1)//因为位序从0(而非1)开始
	{
		if (k == -1 || T.ch[k] == T.ch[j])
		{
			j++;
			k++;
			next[j] = k;
		}
		else
			k = next[k];
	}
}

int Index_KMP(SString S, SString T, int pos)
{
	int next[MAXLEN];
	Get_next(T, next);
	int i = pos, j = 1;
	while (i <= S.length && j <= T.length)
	{
		if (S.ch[i] == T.ch[j])
		{
			++i; ++j;
		}//主串和子串依次匹配下一个字符
		else

			j = next[j];
	}
	if (j > T.length)
		return i - T.length; //匹配成功
	else
		return 0;
}

int main()
{

}

为什么不能使用引用

其实原因我们可能意想不到,在前面的问题(1)当中其实就已经有能解释该现象原因的解答了:

数组不能采用引用格式来传值

根本不存在“元素都是引用的数组”:

本身数组就是用他的首地址来传值的,其首地址代表一大串数组的信息和地址(位置)

而引用传值只是给变量取了一个别名来传值,自然不能(无法)传递整个数组的值

所以只要我们不用引用传数组,自然不会出问题

然而的虽然得到了标准答案,我们还有新的问题没有解决:


(4):传值问题(小结)

 根据同学提醒,这里其实我们很有必要举一反三,重新温习一下

如果想要通过调用函数功能传达改变的值,除了数组以外的变量,不要用形参实参传值

否则会产生最后数值没变的结果


(5):为什么地址(指针)传值的时候及调用函数的时候不能写next[]

next 既代表整个数组,也代表这个数组的头指针


地址传值:

next 前面已经加了 * 符号,再加 [ ]  就相当于要求接收**next类型的实参数据了,显然不符合我们的出发点


调用函数:

这方面其实我也不是很确定:

显然从设计程序的角度而言,我们清楚地知道这个位置需要的是一个数组的首地址,也就是这个数组的头指针

(我觉得)因为next[]无法代表这个数组的首地址,而直接写数组的名称next肯定是鞥狗代表整个数组(也包括首地址)的

另外,我觉得一定要写出next[]形式的首地址的话,其形式效果相当于:&next[0]


(6):调用Get_next函数是否必要

理论上应该是没有调用数据就传不进去,具体有待验证

(7):else语句当中BF算法的语句是什么?

k--?

待解决


PART 2:关于nextval[ j ]

以后再写,答案:

#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit
 
typedef int Status;
#define MAXLEN 255
 
struct SString
	//Sequence String
{
	char ch[MAXLEN + 1]; //存储串的一维数组
	int length; //串的当前长度长度
};
 
void Get_nextval(SString T, int nextval[])
//给你一个子串T,教你逐个算出每个位序对应的next[]
{
	int j = 0,//从头开始算起
		k = -1;
	nextval[0] = -1;//根据公式
	while (j <= T.length)
	{
		if (k == -1 || T.ch[k] == T.ch[j])
		{
			j++;
			k++;
			if (T.ch[k] != T.ch[j])
				nextval[j] = k;
			else
				nextval[j] = nextval[k];
		}
		else
			k = nextval[k];
	}
}
 
int Index_KMP(SString S, SString T, int pos)
{
	int nextval[MAXLEN];
	Get_nextval(T, nextval);
	int i = pos, j = 1;
	while (i <= S.length && j <= T.length)
	{
		if (S.ch[i] == T.ch[j])
		{
			++i; ++j;
		}//主串和子串依次匹配下一个字符
		else
			j = nextval[j];
	}
	if (j > T.length)
		return i - T.length; //匹配成功
	else
		return false;
}
 
int main()
{
 
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/404879.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记录踩过的坑-Git

Git命令克隆很慢原命令&#xff1a;git clone -b r1.13.0 https://github.com/tensorflow/models.git现在替换为&#xff1a;git clone -b r1.13.0 https://github.com.cnpmjs.org/tensorflow/models.git也就是把原 URL 中的 github.com 替换为 github.com.cnpmjs.org&#xff…

设计模式第9式:迭代器模式

前言 我们有很多种方法可以把对象集中到一个集合中&#xff0c;比如列表、堆栈、散列表中。每种集合都有自己的特点和使用时机&#xff0c;但都有一个共同的需求&#xff1a;用户想要遍历这些对象。同时我们并不想用户看到集合的实现&#xff0c;本文将讲解如何让用户遍历对象…

JVM垃圾回收器详解

垃圾收集器没有在规范中进行过多的规定&#xff0c;可以由不同的厂商、不同版本的JVM来实现。由于JDK的版本处于高速迭代过程中&#xff0c;因此Java发展至今已经衍生了众多的GC版本。从不同角度分析垃圾收集器&#xff0c;可以将GC分为不同的类型。1、垃圾回收器分类1.1、按线…

国际安全领域顶会NDSS 2023录稿整理 (下)

隐私计算研习社 NDSS是网络和系统安全领域的四大顶级国际学术会议&#xff08;BIG4&#xff09;之一&#xff0c;第三十届会议于2023年2月27日到3月3日&#xff0c;在美国圣迭戈举办。本文将接着整理剩余论文&#xff0c;并对论文进行分类&#xff0c;感兴趣的小伙伴可以访问论…

【Linux】信号+再谈进程地址空间

目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生&#xff1f; 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais…

pinctrl和gpio子系统

一、pinctrl子系统简介Linux驱动讲究驱动分离与分层&#xff0c;pinctrl和gpio子系统就是驱动分离与分层思想下的产物&#xff0c;pinctrl子系统主要工作内容如下&#xff1a;获取设备树中的pin信息根据获取到的pin信息来设置pin的复用功能根据获取到的pin信息来设置pin的电气属…

Day914.安全认证架构演进:单块阶段 -SpringBoot与K8s云原生微服务实践

安全认证架构演进&#xff1a;单块阶段 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于安全认证架构演进&#xff1a;单块阶段的内容。 讲到安全认证的内容&#xff0c;就必然会提到两个点&#xff1a;认证 和 授权。 认证&#xff1a;我是谁授权&#xff1a;我能…

Spring中的事务@Transactional

Transactional可以添加在方法上 添加在方法上时&#xff0c;表示该方法出现了异常或者报错&#xff0c;而导致之前数据库没有进行回滚事件&#xff0c;也就是说如果在方法中&#xff0c;有报错&#xff0c;但是添加了Transactional 则会开始回滚。 Transactional 在异常被捕获…

剑指 Offer 29. 顺时针打印矩阵

剑指 Offer 29. 顺时针打印矩阵 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2…

【OpenCV技能树】——OpenCV基础

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; 目前正在进行 OpenCV技能树的学习&#xff0c;OpenCV是学习图像处理理论知识比较好的一个途径&#xff0c;至少比看书本来得实在。本专栏文章主要记录学习Op…

Apache apisix默认密钥漏洞(CVE-2020-13945)

目录漏洞描述影响版本漏洞复现声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。漏洞描述 Apache APISIX 是一个动态、实时、高…

LearnOpenGL-模型加载-3.渲染模型

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject 文章目录模型加载重要代码读取3D模型递归处理结点的网格加载纹理优化程序代码Model类加载模型流程例子1&…

【运筹优化】拉格朗日松弛 次梯度算法求解整数规划问题 + Java调用Cplex实战

文章目录一、拉格朗日松弛二、次梯度算法三、案例实战一、拉格朗日松弛 当遇到一些很难求解的模型&#xff0c;但又不需要去求解它的精确解&#xff0c;只需要给出一个次优解或者解的上下界&#xff0c;这时便可以考虑采用松弛模型的方法加以求解。 对于一个整数规划问题&…

Python交通标志识别基于卷积神经网络的保姆级教程(Tensorflow)

项目介绍 TensorFlow2.X 搭建卷积神经网络&#xff08;CNN&#xff09;&#xff0c;实现交通标志识别。搭建的卷积神经网络是类似VGG的结构(卷积层与池化层反复堆叠&#xff0c;然后经过全连接层&#xff0c;最后用softmax映射为每个类别的概率&#xff0c;概率最大的即为识别…

chromium 50 chromium57 版本编译启用 widevine 功能

本实验中 chrome 版本为 57.0.2987.98 01 chromium57 在 win11 版本中启用 widevine 功能 01.01 启用 enable_widevine 选项生成 widevine 相关动态库 在chromium 57 版本中&#xff0c;编译时秩序设置 enable_widevinetrue 即可生成 widevinecdm.dll 和 widevinecdmadapter…

windows下maven更新/安装

写在前面: 我的maven学习的比较早&#xff0c;后面windows文件管理分类的时候&#xff0c;把学习用的全部在一个文件夹了&#xff0c;而这个又不好移动进去。 正好也更新一下maven的版本了&#xff0c;不过和重新安装好像差不多了。 现在写的windows的以后&#xff0c;在看看要…

若依框架部署从零开始2023版(前后端分离)

前言电脑最近重装了一次系统&#xff0c;目前什么都没有安装&#xff0c;记录一下从零开始部署前后端分离版本的若依框架系统先去官网把若依源码拉下来代码克隆若依目前已经有很多的版本了&#xff0c;因为现在开发比较流行前后端分离&#xff0c;因此这里演示前后端分离版本点…

外卖点餐系统小程序 PHP+UniAPP

一、介绍 本项目是给某大学餐厅开发的外面点餐系统&#xff0c;该项目针对校内的学生&#xff0c;配送由学校的学生负责配送。因此&#xff0c;该项目不同于互联网的外卖点餐系统。 该系统支持属于 Saas 系统&#xff0c;由平台端、商家端、用户端、以及配送端组成。 其中&a…

从功能测试进阶自动化测试,爆肝7天整理出这一份超全学习指南【附网盘资源】

因为我最近在分享自动化测试技术&#xff0c;经常被问到&#xff1a;功能测试想转自动化&#xff0c;请问应该怎么入手&#xff1f;有没有好的资源推荐&#xff1f;那么&#xff0c;接下来我就结合自己的经历聊一聊我是如何在工作中做自动化测试的。&#xff08;学习路线和网盘…

盒子拖拽效果,原生js实现

原生js实现拖拽效果 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevic…