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

2024-03-30 03:04
文章标签 算法 语言 查找 kmp bf

本文主要是介绍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值(视频也有讲解,读者自行学习)。

这篇关于C语言查找-----------BF算法KMP算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860323

相关文章

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖