C语言版KMP算法

本文介绍了KMP算法的改进版,重点在于不回溯的主串指针和next数组的计算。next数组用于记录模式串的前后缀交集最长长度,其关键在于递归求解next值。通过next数组,KMP算法能够在主串和模式串不匹配时快速定位。文中提供了完整的C语言代码实现,包括计算next数组和KMP匹配过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对朴素匹配模式算法的改进:

主串指针不回溯只有模式串指针回溯

我们来讲解如何实现求next数组的代码

//求next数组
void getNext(SString S,int *next){
	next[1] = 0;
	int i = 1,j = 0;
	while(i<S.length){
		if(j==0||S.ch[i]==S.ch[j]){
			next[++i] = ++j;
		}else{
			j = next[j];
		}
	}
}

kmp我给他起了另一个名字,叫做看门牌

求next数组,next数组的含义,是字符串的前后缀交集最长的长度加1.

我们需要观察出两点,第一点,比如next[6] = 4,那么next[7]最大只能为5,也就是next[6]+1。

第二点至关重要

如果Pnext[j]≠Pj,那么next[j+1]可能的次大值为next[next[j]]+1如果P_{next[j]} ≠ P_j ,那么next[j+1]可能的次大值为next[next[j]]+1Pnext[j]=Pjnext[j+1]next[next[j]]+1

我们求出next数组的关键就是根据此

递归求出next数组值

接下来是kmp的代码

//kmp代码
int KMP(SString S,SString T){
	int i=1,j=1;
	int next[T.length+1];
	getNext(T,next);
	while(i<=S.length&&j<=T.length){
		if(j==0||S.ch[i]==T.ch[j]){
			++i;
			++j;
		}else{
			j = next[j];
		}
	}
	if(j>T.length){
		return i-T.length;
	}else{
		return 0;
	}
}

开始判断 S.ch[i]==T.ch[j] ,如果相等 ,那么继续比较后续字符,如果不相等,模式串进行回溯,当跳出循环,即已经匹配完所有字符,如果j已经大于T的长度时说明成功,反之失败

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define MAXLEN 255

typedef struct{
	char ch[MAXLEN];
	int length;
}SString;

//输入字符串
void assign(SString *S){
	int i = 1;
	char x;
	scanf("%c",&x);
	while(x!='\n'){
		S->ch[i++] = x;
		scanf("%c",&x);
	}
	S->length = i-1;
}
//打印字符串
void print(SString S){
	for(int i=1;i<=S.length;i++){
		printf("%c",S.ch[i]);
	}
	printf("\n");
}
//求next数组
void getNext(SString S,int *next){
	next[1] = 0;
	int i = 1,j = 0;
	while(i<S.length){
		if(j==0||S.ch[i]==S.ch[j]){
			next[++i] = ++j;
		}else{
			j = next[j];
		}
	}
}
//kmp代码
int KMP(SString S,SString T){
	int i=1,j=1;
	int next[T.length+1];
	getNext(T,next);
	while(i<=S.length&&j<=T.length){
		if(j==0||S.ch[i]==T.ch[j]){
			++i;
			++j;
		}else{
			j = next[j];
		}
	}
	if(j>T.length){
		return i-T.length;
	}else{
		return 0;
	}
}
int main(){
	SString S,T;
	printf("请输入主串:\n");
	assign(&S);
	printf("请输入模式串:\n");
	assign(&T);
	printf("匹配到的位置:%d",KMP(S,T));
	return 0;
}

测试

成功在这里插入图片描述
失败
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Violent-Ayang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值