用C语言实现KMP算法

KMP 算法中对 next 数组的理解

借鉴自大佬:KMP 算法中的 next 数组推导(图解 + 代码实现)_next数组-优快云博客

next 数组的意义

此处 next[j] = k则有 k 前面的浅蓝色区域和 j 前面的浅蓝色区域相同;

next[j] 表示当位置 j 的字符串与主串不匹配时,下一个需要和主串比较的字串位置在 next[j] 处;有下图:

image-20220328181044480

若当前位置 j 与主串某一个字符不匹配,则下一次比较的是 K 与主串的当前位置,这个 K 也就是 next[j];由于两个浅蓝色区域相同,因此 K 前面的区域肯定与主串相同,不需比较;如下图:

image-20220328181606603

由上图可知,K 前面的区域不需比较;

所以我们next的作用就是在碰到主串与子串不匹配的情况(这里把 0 ~ j-1 看做主串,k~j-1 看做子串)下主串的 i 不动,子串的 j 返回到对应的next位置。然后不断递归直到 j 到了第一个位置或者该位置与 i 匹配。这样可以避免多余的匹配提高代码的效率。

kmp算法的思路和next大同小异就是遍历匹配主串与子串遇到不匹配的情况就调用next。当j==子串的长度的时候说明匹配成功了。如果 i 超出了主串的长度说明没有找到匹配的子串。

源码

注释全写在代码里了

#include<stdio.h>
#include<string.h>
void getnext(char a[],int next[])
{
	int n=strlen(a);
	next[0]=-1;
	next[1]=0;
	int t=0;	//t为当前索引的前一位的最大相同前后缀的长度及应该回溯的位置(该位置的值对比当前索引的前一位的值)
	for(int i=2;i<n;i++){
		t=next[i-1];	//每次先给t赋值为前一位的next值
		while(t>=0&&a[i-1]!=a[t]){
		//当a[i-1]的值与前一位对应的next值不相同时在去找前面的next值直到
		//找到第一位(t==-1)及没有最大相同前后缀(该位置的next值就应该是0)
		//或者有一个next的值与a[i-1]相等时退出循环(该位置的next值就应该是当前回溯找到的next(t)+1)
			t=next[t];
		}
		if(a[i-1]==a[t] || t==-1){
			next[i]=t+1;
		}
	}
}
int kmp(char s[],char t[])	//s为主串,t是模式串
{
	int ls=strlen(s);
	int lt=strlen(t);
	int next[10000];
	getnext(s,next);
	int i=0,j=0;
	for(;i<ls;i++){	//外层是遍历主串
		while(j>0&&s[i]!=t[j]){	//如果匹配不成功主串的i不动j回溯到next(最大相同前后缀)
			printf("%d	%d\n",i,j);
			printf("%c	%c\n",s[i],t[j]);
			j=next[j];
		}
		if(s[i]==t[j])	//如果主串与模式串匹配成功i,j后移
		{
			printf("%d	%d\n",i,j);
			printf("%c	%c\n",s[i],t[j]);
			j++;
		}
		if(j==lt)	//如果子串遍历到了最后一位搜索结束返回值
		{
			return i-j+1;
		}
	}
	return -1;	//匹配不成功
}
int main()
{
	char s[10000],t[10000];
	gets(s);
	gets(t);
	int next[10000];
	getnext(t,next);
	for(int i=0;i<strlen(t);i++){
		printf("%d	",next[i]);
	}
	printf("\n");
	int x=kmp(s,t);
	printf("	%d		\n",x);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值