KMP算法

本文详细阐述了KMP算法的优化过程,并通过代码实例展示了如何在文本匹配中高效应用该算法。同时,文章指出算法在实际编程中可能遇到的问题及解决方案。

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

KMP算法是测试智商的好办法,事实证明我智商捉急。

自己看思路写了好久才写出的代码,没有优化。


一个同学说我写的abcabaa最后一个出错了,由于没有照顾到前面有一堆相同然后有一个不同的情况。已经解决好了。


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void get_next(char *t, int len, int next[]) {

	next[0] = -1;
	int k = 0;
	int isHaveSameStrAndOneDiffChar = 0;
	for (int j = 1; j < len; ) {
		if (k == 0&& isHaveSameStrAndOneDiffChar==0) {
			if (t[j] == t[k]) {
				next[j] = k;
				j++;
				k++;
			}
			else {
				next[j] = 0;
				j++;
			}
		}
		else {
			if (isHaveSameStrAndOneDiffChar == 0) {
				if (t[j - 1] == t[k - 1] && t[j] == t[k]) {
					next[j] = k;
					j++;
					k++;
				}
				else if (t[j - 1] == t[k - 1] && t[j] != t[k]) {
					next[j] = k;
					j++;
					k = next[k];
					isHaveSameStrAndOneDiffChar = 1;
				}
			}
			else if(isHaveSameStrAndOneDiffChar == 1){
				
				if (t[j - 1] == t[k]) {
					k++;
					isHaveSameStrAndOneDiffChar = 0;
				}
				else {
					k = next[k];
					if (k == -1) {
						k++;
						isHaveSameStrAndOneDiffChar = 0;
					}
				}
			}
			
		}
	}

	for (int i = 0; i < len; i++) {
		printf("%d ", next[i]);
	}
	printf("\n");
}

int kmp(char *s, char *t) {
	int s_len = strlen(s);
	int t_len = strlen(t);
	int *next = malloc(t_len * sizeof(int));
	get_next(t, t_len, next);

	int i = 0, j = 0;
	while (i <= s_len - t_len) {
		int k = i;
		int j = 0;
		while (k < s_len && j < t_len) {
			if (j == -1) {
				i = k + 1;
				break;
			}
			else if (s[k] == t[j]) {
				k++;
				j++;
			}
			else
				j = next[j];
		}
		if (j == t_len)
			return k-t_len;
	}
	return -1;
}

int main() {
	char *s = "abcaabbabcabdacaabcaabbabcabaac";
	char *t = "abcaabbabcabaac";
	printf("%s", s+kmp(s, t));
}


时隔半年,来一个优化后注释了的版本

#include<iostream>

void get_next(char *t, int t_len, int *next)
{
	
	next[0] = -1;//第0个不相同,只能前进,主指针只能前进


	//j,k代表包括字符j-1和k-1前的相同,求字符j和k不相同时的next[j]
	int j = 0;//主指针,计算从1开始,由于先++,所以设为0
	int k = -1;//开始设为-1是因为

	while (j < t_len)
	{
		
		if ((k == -1) || (t[j] == t[k]))//-1情况代表连模式串第一个字符也不相同,所以下一个字符从头比较,next为0,从头比较,这里合并了两种情况
		{
			++j;
			++k;
			next[j] = k;//k-1个前面是相同的,所以直接比较k
		}
		else
		{
			
			k = next[k];//当前字符不相同,求前面的相同的下一个字符
		
		}
	}

	for (int i = 0; i < t_len; i++)
	{
		printf("next[%d]=%d\n",i+1, next[i]+1);
		
	}

}

int kmp(char *s, char *t, int s_len, int t_len)
{
	int next[400];
	int i = 0;//主指针
	int j = 0;//模式指针,一开始当然是从0开始比较
	
	get_next(t, t_len, next);
	while (i < s_len && j < t_len)
	{
		if (j == -1 || (s[i] == t[j]))//-1代表连第一个也不相同,前进,从头比较。
		{
			i++;
			j++;

		}
		else
			j = next[j];//
	}


	if (j == t_len)
	{
	//	printf("%d %d test\n", i, t_len);
		return i - t_len;
	}
	else
		return -1;



}



int main()
{
	char s[2000];
	char t[400];
	scanf("%s", s);
	scanf("%s", t);
	
	
	printf("模式在文本中的位置是%d\n", kmp(s, t,strlen(s),strlen(t))+1);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值