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;elsereturn -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值(视频也有讲解,读者自行学习)。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS实战开发-实现Ability内页面间的跳转和数据传递。

介绍 本篇Codelab基于Stage模型下的Ability开发&#xff0c;实现Ability内页面间的跳转和数据传递。 最终效果图如下&#xff1a; 相关概念 页面路由&#xff1a;提供通过不同的url访问不同的页面&#xff0c;包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、…

通讯录改进———动态版本

在上一篇博客中讲完了动态内存分配&#xff0c;这时候我们就可以改进之前写的通讯录了&#xff0c;可以将其升级为动态内存的版本&#xff0c;既不用担心联系人满了&#xff0c;也不用担心内存浪费太大。 要将其改为动态版本主要是两件事&#xff0c;首先初始化的时候我们要动…

算法打卡day31|贪心算法篇05|Leetcode 435. 无重叠区间、763.划分字母区间、56. 合并区间

算法题 Leetcode 435. 无重叠区间 题目链接:435. 无重叠区间 大佬视频讲解&#xff1a;无重叠区间视频讲解 个人思路 和昨日的最少箭扎气球有些类似&#xff0c;先按照右边界排序&#xff0c;从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区间的个数就是需要移除的…

Image-Adaptive YOLO for Object Detection in Adverse Weather Conditions(IA-YOLO)

1、总体概述 基于深度学习的目标检测在常规条件的数据集可以获得不错的结果&#xff0c;但是在环境、场景、天气、照度、雾霾等自然条件的综合干扰下&#xff0c;深度学习模型的适应程度变低&#xff0c;检测结果也随之下降&#xff0c;因此研究在复杂气象条件下的目标检测方法…

代码随想录算法训练营 DAY 24 | 回溯理论基础 77.组合 + 剪枝优化

回溯理论 回溯法就是递归函数&#xff0c;纯暴力搜索 解决的问题 组合&#xff08;无顺序&#xff09; 1 2 3 4 给出大小为2的所有组合 切割字符串 子集问题 1 2 3 4&#xff0c;子集有1 2 3 4,12,13,14&#xff0c;…123 124… 排列&#xff08;有顺序&#xff09; 棋盘…

K8s Pod亲和性、污点、容忍度、生命周期与健康探测详解(中)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 在上一章节中&#xff0c;我们详细探讨了Pod的亲和性&…

root_fs文件系统结构分析和内核加载流程

目录 概述 1 根文件系统下目录介绍 2 文件系统内容分析 2.1 etc/inittab代码分析 2.2 /etc/init.d/rcS 代码分析 2.3 /etc/mdev.conf代码分析 2.3.1 功能概述 2.3.2 /etc/mdev.conf的详细代码 2.4 /etc/init.d/rcS的源代码文件 3 分析内核中加载root_fs的流程 3.1 调…

centos7配置阿里云的镜像站点作为软件包下载源

目录 1、备份 2、下载新的 CentOS-Base.repo 到 /etc/yum.repos.d/ 3、测试 阿里镜像提供的配置方法&#xff1a;centos镜像_centos下载地址_centos安装教程-阿里巴巴开源镜像站 1、备份 [rootlocalhost ~]# mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentO…

[Linux]基础IO(上)--理解文件系统调用、文件描述符、万物皆文件

一、文件的理解 每种语言都有进行文件操作的函数接口&#xff0c;例如C语言的fopen、fwrite、fprintf等等&#xff0c;但是进行文件操作的前提是代码已经跑起来&#xff0c;因为文件的打开与关闭要通过CPU来运行程序代码&#xff0c;所以打开文件的本质是进程打开文件&#xff…

2024 ccfcsp认证打卡 2021 12 01 序列查询

2021 12-1 序列查询 题解1题解2区别第一种算法&#xff1a;第二种算法&#xff1a; 题解1 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);// 输入n表示商品数目&#xff0c;N表示总数int n sc.n…

ChatGPT如何升级为GPT-4在国内

通过 WildCard 可以把ChatGPT升级为GPT-4 地址 1: 2155 Bailey Hill Rd 城市: Eugene 邮编: 97405 州: Oregon ChatGPT Plus/Team 一键升级&#xff0c;几分钟即可自动升级到 ChatGPT Plus。 选择我的邮箱账号符合要求 复制这个页面的链接即可 复制上面的link 到请在…

Harbor部署

Harbor部署 下载和安装 github下载地址&#xff1a;https://github.com/goharbor/harbor/releases 解压和配置 # 解压tgz包 tar -zxvf harbor-offline-installer-v2.10.1.tgz # 进入目录后进行复制配置文件 cd harbor/ # 创建一个配置文件 cp harbor.yml.tmpl harbor.yml …