KMP算法之我见(初解)

2024-08-28 23:18
文章标签 算法 kmp 之我见 初解

本文主要是介绍KMP算法之我见(初解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

几天前看到KMP算法的时候,头大如麻,略读一遍,决定跳过,学完了整章串、数组、矩阵和广义表之后回头专心研究KMP算法。

在学习这本《数据结构》的前几章的时候我就开始对这本教程有点失望了,当初在图书馆里对比了十几本教程选择了它,主要原因是它图解较多,便于理解,但是细读发现它的代码不够讲究,实用性不强,可能是我经验匮乏吧,反正这本教材的堆栈部分我很不满意,代码可用性太小,相较其他版本的结构体实现堆栈劣势明显。言归正传,因上述原因,我没有再研究本书,而是看了视频教程,小甲鱼的教程让我对NEXT数组有了直观认识,但是在后来的NEXT数组的实现和KMP算法优化上依然云雾缭绕。

 

NEXT数组核心思想:

当前匹配点失配,模式串该前进几位与当前的主串匹配点重新进行比较,而NEXT数组元素值就是前进的位数。假设模式串在p9点失配,则p0p1p2p3p4p4p5p6p7p8与当前对应的主串字符是一一相等的,下一步改用模式串第几位取代P9位重新对比呢,关键看p0p1p2p3p4p4p5p6p7p8的前缀子串和后缀子串,前后缀子串分别对应为:

P0 —— P8

P0P1 —— P7P8

P0P1P2 —— P6P7P8

……

P0P1P2P3P4P5P6P7 —— P1P2P3P4P5P6P7P8

分别判断这些前缀子串后缀子串对是否相等,如果相等,下一次匹配的时候,就用前缀子串的取代后缀子串的位置,即模式串整体前进了strlen(前后缀子串)个位数.

有了这个思路,就开始通过代码实现NEXT数组的求值。

 

(事实上这个思路过程有些繁琐,所以牵扯到后续的优化问题,后话暂且不提)

 

NEXT数组求法,及测试函数如下:

 

//测试:-1 0 0 0 1 2 3 4 5 0 1   abcabcabbac
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 12
int FindNext(char *t,char x);
int main()
{
char str[MAX] = "abcabcabbac";
char x;       //失配点
printf("当前模式串:%s \nNEXT数组求值过程如下:\n\n",str);
for(x=0;x<MAX-1;x++)
{
printf("next[%d] = %d \n\n",x,FindNext(str,x));
}
return 0;
}
//传入一个模式串t,t串当前失配点字符位置x,返回next值,默认数组长度宏定义MAX
int FindNext(char* t,char p)
{
char i,j;
char qtr[MAX];
char ptr[MAX];
char n=0;
char k=0;
if(p==0)	
{
return -1;
}
for(i=0;i<p-1;i++)
{
//处理前缀子串
for(k=0;k<=i;k++)
{
qtr[k] = t[k];
}
qtr[k]='\0';
//处理后缀子串
k=0;
for(j=p-i-1;j<=p-1;j++)
{
ptr[k] = t[j];
k++;
}
ptr[k]='\0';
printf("前缀子串:%-15s    后缀子串:%-15s\n",qtr,ptr);
if(strcmp(qtr,ptr)==0) n=strlen(qtr);
}
return n;
}


 

能求出NEXT数组,接下来就是利用NEXT数组值进行KMP算法。

 

思路关键如下:

设主串为ZHU_STR[100],模式串为MO_STR[10],则从ZHU_STR[0] == MO_STR[0] ?开始比较,相等,则两串同时前进一位i,对比各串的第二个字符,若不等,则当前匹配点为失配点,根据NEXT数组值向前移动模式串,则主串当前点对应到新的模式串字符,重新判这两个字符相等与否,重复上述过程。

 

把握住,每一次对比只有两个字符,且只有两种结果,等或不等,等该怎样?(同时前进对比下一位)不等该怎样?(模式串前进)

 

实现代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 12
int FindNext(char *t,char x);
int main()
{
char z_str[] = "asfsabc";
char m_str[] = "abc";
char z_num=0;					//主串当前匹配点
char m_num=0;				         //模式串当前匹配点
char len_z = strlen(z_str);
char len_m = strlen(m_str);
char p=0;                                              //模式串失配点
char i=0;
while(z_num<len_z && m_num < len_m)                    //依次用主串的每一个字符和子串对比,主串不回溯
{					         //每次对比区别为子串的前进位数,每一次对比只有两种结果
if(z_str[z_num] == m_str[m_num] )		//相同则,同时+1,
{										
z_num++;
m_num++;
}
else					//不同则,调用NEXT数组决定下一步子串前进多少个字符
{
p = m_num;
i = FindNext(m_str,p);
if(i==-1)				//next数组为-1,则子串置0重头来,主串+1(理解如下)
{				//假设模式串p[0]前一位为p[-1],下一次比较要让p[-1]与当前匹配点比较
m_num = 0;		//那不就是主串前进一步和p[0]进行对位匹配么。
z_num++;
}
else				//否则,主串不变,子串向前滑动相应的位数
m_num = i;
}
if(m_num == len_m)						 
}
if(m_num == len_m)							
{
printf("成功匹配!\n起始位置是:%d\n",z_num-len_m);
}
else
{
printf("没有匹配成功!\n");				
}
return 0;
}
//传入一个模式串t,t串当前失配点字符位置x,返回next值,默认数组长度宏定义MAX
int FindNext(char* t,char p)
{
char i,j;
char qtr[MAX];
char ptr[MAX];
char n=0;
char k=0;
if(p==0)	
{
return -1;
}
for(i=0;i<p-1;i++)
{
//处理前缀子串
for(k=0;k<=i;k++)
{
qtr[k] = t[k];
}
qtr[k]='\0';
//处理后缀子串
k=0;
for(j=p-i-1;j<=p-1;j++)
{
ptr[k] = t[j];
k++;
}
ptr[k]='\0';
if(strcmp(qtr,ptr)==0) n=strlen(qtr);
}
return n;
}


 

KMP算法实现总结:

1、写next数组的时候就失误了,每次传回的是一个元素值,而不是一个数组,导致主函数执行是不停调用子函数去求NEXT值做出反应,应该让NEXT函数只运行一次返回一个整个的NEXT数组供主函数查找,这样简化了很多步奏。

2、NEXT数组的求法上过于繁琐,有待研究之后下期博文优化改进。

3、感觉程序思路好像还算明白,但是相对其他的KMP算法实现代码量大了不少。

这篇关于KMP算法之我见(初解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “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. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

codeforces535D:Tavas and Malekas(KMP)

(i-1 , i)有重合的时候 ,从第i位开始的子串必须是模式串的前缀。 而同时,从第i位开始的子串本来就已经是模式串的后缀了。 typedef long long LL ;const int maxn = 1000008 ;int next[maxn] ;void getnext(char s[]){int len = strlen(s) ;next[0] = -1 ;i