C语言查找-----------BF算法KMP算法

1.问题引入

有一个主字符串,有一个子字符串,要求我们寻找子字符串在主字符串里面开始出现的位置;

2.BF算法

BF算法就是暴力算法,这个做法虽然效率不高,但是按照我们传统的思路依然能够得到结果,接下来我们使用C语言实现这个查找的过程;

#include<stdio.h>
#include<assert.h>
#include<string.h>
//返回字串在主串里面的位置
//没有找到返回-1;
int BF(char* str, char* sub)
{
	assert(str && sub);
	if (str == NULL || sub == NULL)
	{
		return -1;
	}
	int lenstr = strlen(str);
	int lensub = strlen(sub);
	int i = 0;
	int j = 0;
	while (i < lenstr && j < lensub)
	{
		if (str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (j >= lensub)
	{
		return i - j;
	}
	else
	{
		return -1;
	}
}
int main()
{
	printf("%d\n", BF("abcabdefabchd","abch"));
	printf("%d\n", BF("abceabcd", "abcd"));
	printf("%d\n", BF("abcabcabc", "abcdefgh"));
	return 0;
}

这段代码的逻辑是这样的:

(1)我们首先定义一个函数BF,我们这个函数的作用就是寻找子串在主串里面的位置,我们可能会在主串里面找到字串,找到就会返回子串在主串里面的位置下标,如果找不到就会返回-1;

(2)我们以代码主函数里面的第一个作为案例,我们使用*str代表主串,*sub代表子串;

(3)我们首先进行断言,断言的话就要包含对应的头文件,如果子串或者主串是空的,那么我们就直接返回-1,因为这样的话肯定找不到;

(4)我们定义i遍历主串,使用j遍历子串,我们使用strlen求两个字符串的长度(这里也是要包含对应的头文件的,如果i<主串的长度而且j小于子串的长度,说明我们正在进行遍历,我们需要在这样的情况下进行判断;

(5)如果i>=主串的长度,证明主串已经找完了,这个时候就是没有找到返回-1,如果j>=子串的长度,说明我们已经找到了,这个时候就要返回子串在主串的位置下标;

(6)接下来我们需要计算这个下标的变化,以代码主函数里面的第一个作为案例,i指向的是主串的第一个字符,j指向的是字串的第一个字符,第一个都是a,i++,j++,第二个都是b,i++,j++,第三个都是c,i++,j++,第四个就不一样了,这个时候我们需要重新寻找,i和j都要回退,j肯定是回退到0下标,i应该从第二个字符开始,因为我们刚刚是从第一个开始找,找不到,那么这个2下标应该如何表示呢?我们首先要清楚的是i和j的移动的个数是一致的,j已经走了j个,那么i-j就可以表示i开始的位置,但是这个位置找不到,我们就要从他的下一个位置开始找,我们就可以用i-j+1进行表示主串里面下标回退的位置;我们设置一个循环,依次进行,直到主串遍历完成或者子串遍历完成就停止退出循环;

(7)如果是j>=子串长度,说明可以在主串里面找到,我们直接返回i-j就可以找到第一个下标了,这个时候,就不需要加一了,因为i-j+1是找不到的时候j回退的位置;

(8)还有一个我们需要注意的细节就是我们在回退的时候,必须先让i回退,再让j回退,因为j如果回退到0,i-j+1显然就不是我们想逃回退的下标了,我们就是想要利用j的下标计算的,如果先把j置为0,肯定是无法得到我们想要的结果的。

3.KMP算法

我们想要了解KMP算法,就必须知道他和我们普通的暴力算法有什么不同之处,其实KMP算法是三个大佬发现的,KMP分别是这3个大佬名字的第一个字母(我们了解一下就可以了),他和普通算法的不同点就在于,

(1)我们上面介绍的BF算法,如果匹配错误,i返回i-j+1下标,我们的KMP算法是不会回退的;

(2)BF算法的j回退到0下标,这个地方KMP是不会回退到0的,而是回退到一个我们指定的位置,这个回退的指定的位置是KMP算法的亮点,也是难点,只有真正的了解这个回退的特定位置的计算方法,我们才能掌握KMP算法的精髓,再官方的算法里面,每个主串的元素都会对应一个回退的位置,因此我们把每个元素回退的位置放到数组里面,我们称这样的一个数组叫做Next数组

(本人KMP博客是根据下面的这位UP视频所写,除了手动求解我的博客有所涉及解析,其他的代码求解都是简写的(因为我对于其中的诸多细节也不是很通透明了,就不误人子弟了),读者可自行进行系统学习,超详细,链接如下)

【完整版】终于有人讲清楚了KMP算法,Java语言C语言实现_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1UL411E7M8/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=a432cb5e896a2b96961d1f73a6ebe0ca

(3)我们已经知道了Next数组这个概念,我们接下来学习一下这个Next数组里面每个元素的计算方法:

这个就是回退的规则,可能难以理解,我们通过一些具体实例理解一下,

对于初学者我们必须要清楚的是,这个算法是如何用的,通俗的讲,对于一个子串,我们应该看他是否和主串的字符相同,如果相同就进行下一个,如果不相同,我们的子串j就要回退到一个特定的位置,这个位置的求法就是我们要知道的,接下来我们讨论的和练习的都是这个回退下标的计算

可能到这个地方,你大概已经知道了,我们的每一个字符都有一个特定的回退位置,这个组成一个数组,我们称之为Next数组,例如我们的第一个字符回退到2下标的位置,我们就写作Next[0]=2,第二个字符回退到4下标的位置,我们就写作Next[1]=4,以此类推,我们根据规则先手动的求一下这个Next数组,我们现在就要知道怎么手动求解,我们随便给一个字符数组

我们的规定是第一个元素回退到-1下标,第二个回退到0下标(这个记住即可,后面会有用处,可以简单的理解为这个就是规定),从第三个开始,我们就可以根据规则手动求解,第三个c回退到哪个下标,是以a开始,以他前面的b结尾的两个相同的子串,因为只有一个ab,所以我们next[2]=0;第四个字符,我们要找到以a开始,以c结尾的两个字符串,因为这里只有abc,所以next[3]=0;下一个b字符,我们要找到以a开始,以a结尾的两个字符串,他们的长度是1,所以next[4]=1,同理next[5]=2,这样我们就手动求解了这个next数组;

#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
void getnext(char* sub, int* next, int lensub)
{
	next[0] = -1;
	next[1] = 0;
	int i = 2;
	int k = 0;
	while (i < lensub)
	{
		if ((k == -1) || sub[i - 1] == sub[k])
		{
			next[i] = k + 1;
			i++;
			k++;
		}
		else
		{
			k = next[k];
		}
	}
}
int KMP(char* str, char* sub, int pos)
{
	assert(str && sub);
	int lenstr = strlen(str);
	int lensub = strlen(sub);
	if (lenstr == 0 || lensub == 0)
		return -1;
	if (pos < 0 || pos >= lenstr)
		return -1;

	int* next = (int*)malloc(sizeof(int) * lenstr);
	assert(next);
	getnext(sub, next, lensub);
	int i = 0;
	int j = 0;
	while (i < lenstr && j < lensub)
	{
		if (j == -1 || str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j >= lensub)
		return i - j;
	else
		return -1;
}
int main()
{
	printf("%d", KMP("abdefabc", "abc", 0));
	return 0;
}

这段代码涉及到了代码表示我们手动计算的值,还有数组的越界访问,找不到和自己一样的字符就会不停的回退,直到相同才会停止,详情请根据视频自行学习;

【完整版】终于有人讲清楚了KMP算法,Java语言C语言实现_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1UL411E7M8/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=a432cb5e896a2b96961d1f73a6ebe0canext数组的优化:就是如果不一样,要不停的回退,我们的优化就是一次性回退到位,回退位置的字符和该字符一样,就写回退位置的nextval值,不一样就写自己的next值(视频也有讲解,读者自行学习)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 523. 连续的子数组和

解题思路 相关代码 class Solution {public boolean checkSubarraySum(int[] nums, int k) {int s[] new int[nums.length1];for(int i1;i<nums.length;i) s[i]s[i-1]nums[i-1];Set<Integer> set new HashSet<>(); for(int i2;i<nums.length;i){set.ad…

filebox在线文件管理工具V1.11.1.1查分吧修改自用版免费分享[PHP]

* 基于:https://down.chinaz.com/soft/35899.htm * 查分吧 修改自用版今日对外分享(自2016年1.10版本以来一直用他云开发:Web环境即时看效果) * 也可以用于本人很多txt/csv通用查询系统的在线管理后台管理数据 * 默认登陆账号filebox密码nidemima * 修改账号密码:21-22行;获取…

Java八股文(K8S)

Java八股文のK8S K8S K8S 请解释什么是Kubernetes&#xff1f; Kubernetes是一个开源的容器编排和管理工具&#xff0c;用于自动化部署、扩展和管理容器化应用程序。 请解释Kubernetes中的Pod、Deployment和Service之间的关系。 ● Pod是Kubernetes的最小部署单元&#xff0c;…

练习 13 Web [极客大挑战 2019]Secret File

php伪协议请求&#xff0c;php代码审计 参考&#xff1a;BUUCTF__[极客大挑战 2019]Secret File_题解 没有任何上传和登录页面 查看前端源码 发现 <a id"master" href"./Archive_room.php" style"background-color:#000000;height:70px;width:20…

【java9】java9新特性值之集合不可变实例工厂方法

Java9为集合接口List、Set、Map提供了创建不可变实例的工厂方法。这些工厂方法为便利而生&#xff0c;以简单的方式创建这些集合的不可变实例。 Java9之前创建不可变集合 在Java9之前&#xff0c;创建不可变集合通常需要通过其他方式&#xff0c;比如使用Collections.unmodif…

day4 linux上部署第一个nest项目(java转ts全栈/3R教室)

背景&#xff1a;上一篇吧nest-vben-admin项目&#xff0c;再开发环境上跑通了&#xff0c;并且build出来了dist文件&#xff0c;接下来再部署到linux试试吧 dist文件夹是干嘛的&#xff1f; 一个pnpn install 直接生成了两个dist文件夹&#xff0c;前端admin项目一个&#xf…

用Kimichat快速识别出图片中的表格保存到Excel

如果有一张图片格式的表格&#xff0c;想要快速复制到Excel表格中&#xff0c;那么一般要借助于OCR工具。之前试过不少在线OCR工具&#xff0c;识别效果差强人意。其实&#xff0c;kimichat就可以非常好的完成这个任务。 下面是一张研报中的表格&#xff0c;只能以图片形式保存…

153 Linux C++ 通讯架构实战8 ,日志打印实战,设置时区,main函数中顺序调整

日志打印实战 //日志的重要性&#xff1a;供日后运行维护人员去查看、定位和解决问题&#xff1b; //新文件&#xff1a;ngx_printf.cxx以及ngx_log.cxx。 //ngx_printf.cxx&#xff1a;放和打印格式相关的函数&#xff1b; //ngx_log.cxx&#xff1a;放和日志相关…

【计算机考研】数学难,到底难在哪里?看这一篇深度分析

数一和数二的难度系数都不在一个重量级&#xff01; 数一这货&#xff0c;容量真不是数二能比的&#xff01;除了高数、线代这些常规操作&#xff0c;还要啃概率论与数理统计这本大厚书&#xff0c;简直是让人头大&#xff01; 考研数学嘛&#xff0c;大家都知道&#xff0c;…

前端是什么

1.前端的概念 1.1 前端的定义 对于网站来说&#xff0c;通常是指网站的前台部分&#xff0c;包括网站的表现层和结构层&#xff08;通俗点就是用户可以看到的部分&#xff09;。总结一下&#xff0c;浏览器、APP、应用程序的界面展现和用户交互就是前端1.2 前端的作用 前端工程…

element跑马灯/轮播图,第一页隐藏左边按钮,最后一页隐藏右边按钮(vue 开箱即用)

图示&#xff1a; 第一步&#xff1a; <el-carousel :class"changeIndex0?leftBtnNone:changeIndeximgDataList.length-1? rightBtnNone:" height"546px" :autoplay"false" change"changeNext"><el-carousel-item v-for…

Android预置应用基础

目录 一、应用预置二、应用预置分区三、编译规则3.1 Android.mk3.2 Android.bp 一、应用预置 预置指智能终端设备出厂前&#xff0c;将文件预先安装到系统中。预置对象包括应用程序、可执行文件、so库&#xff08;.so 文件&#xff09;、jar 包等。 预置方式有以下两种&#…

交换机干道链路

干道链路是用于交换机之间或交换机与路由器之间互连的物理链路。干道链路传输的数据帧都必须打上Tag&#xff0c;便于设备识别数据帧所属的VLAN。因此一条干道链路可以承载多个VLAN的数据帧&#xff0c;如图1-1所示。 图1-1 干道链路功能示意图 干道链路可以透传VLAN。换言之&…

2023年后端面试总结

备注&#xff1a;这篇文章是我在2023年年初在自己的网站上写的&#xff0c;最近在迁移技术文章&#xff0c;我感觉这个也是和咱程序员相关&#xff0c;所以今天就决定把它迁移过来。 .......................................................................分割线..........…

代码随想录算法训练营 Day31 贪心算法1

Day31 贪心算法1 理论基础 贪心算法的本质&#xff1a;找到每个阶段的局部最优&#xff0c;从而去推导全局最优 贪心的两个极端&#xff1a;要么觉得特别简单&#xff0c;要么觉得特别难 贪心无套路 不像二叉树、递归&#xff0c;有固定模式 贪心题目的思考方式 做题的时候…

HarmonyOS实战开发-使用List组件实现导航与内容联动的效果。

1 卡片介绍 使用ArkTS语言&#xff0c;实现一个导航与内容二级联动的效果。 2 标题 二级联动&#xff08;ArkTS&#xff09; 3 介绍 本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能&#xff1a; 切换左侧导航&#xff…

SpringMVC源码分析(七)--数据绑定工厂

1.数据绑定工厂的使用 数据绑定工厂能够创建数据绑定器,将数据绑定到对象中,比如说当接收到请求时,经过http协议解析后数据刚开始都是字符串,此时我们希望将这些属性进行类型转换,并为对象赋值,示例如下: 1)先创建两个实体类Student和Teacher @Getter @Setter @ToSt…

学习鸿蒙基础(10)

目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏&#xff1a; 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…

[Python人工智能] 四十五.命名实体识别 (6)利用keras构建CNN-BiLSTM-ATT-CRF实体识别模型(注意力问题探讨)

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。这篇文章将详细结合如何利用keras和tensorflow构建基于注意力机制的CNN-BiLSTM-ATT-CRF模型,并实现中文实体识别…

基于单片机宿舍防火防盗系统的设计

**单片机设计介绍&#xff0c;基于单片机宿舍防火防盗系统的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机宿舍防火防盗系统的设计概要主要涉及单片机技术的应用&#xff0c;以实现对宿舍环境的防火和防盗功能的…