KMP算法详解

本文探讨了KMP算法,一种用于高效字符串匹配的改进算法,通过next数组存储模式串局部匹配信息,以减少比较次数。作者给出了算法思想、next和nextval数组的计算以及实际的KMP函数实现,并展示了如何应用在主串和模式串的匹配中。

作者: sleepygod
日期: 10-20
也许 不负光阴就是最好的努力 而努力就是最好的自己

01b5a5f231c7c866768410af8a2d993

KMP算法简单实现

1.算法思想

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

image-20221020182844984

区别:KMP 和 BF 唯一不一样的地方在,我主串的 i 并不会回退,并且 j 也不会移动到 0 号位置

具体实现如下:

首先我们求出next数组,因为next数组记录每一次回溯的位置

image-20221020183354376

为了方便计算,我将next数组每一个值与上述相比都减一.

next[0]=-1,next[1]=0,接下来,就判断p[i-1]是否与p[next[i-1]]是否相等,如相等则next[i]=next[i-1]+1;如不相等,则继续回溯,直至-1位置.

next数组优化 如果p[i]=p[next[i]],则,nextval[i]=nextval[next[i]],否则nextval[i]=next[i].

2.算法实现

int* getnext(const char* p)
{
	int* next = (int*)malloc(strlen(p) * sizeof(int));
	*(next+0) = -1;
	*(next + 1) = 0;
	for (int i = 2; i < strlen(p); i++)
	{
		int tmp = next[i - 1];
		
			while (tmp>-1)
			{
				if (p[i - 1] == p[tmp]) 
				{
					break;
				}
				else
				{
					tmp = next[tmp];
				}
			}
			next[i] = tmp + 1;
	}
	return next;
}
int *getnextval(const char *p,const int *next)
{
	int* nextval = (int*)malloc(strlen(p) * sizeof(int));
	*nextval = -1;
	for (int i = 1; i < strlen(p); i++)
	{
		if (p[i] == p[next[i]])
		{
			nextval[i] = nextval[next[i]];
		}
		else
		{
			nextval[i] = next[i];
		}
	}
	return nextval;
}

void KMP(const char* p1,const char* p2)
{
	int* next = nullptr;
	next = getnext(p2);
	int* nextval = nullptr;
	nextval = getnextval(p2, next);
	int answer = -1;
	int i = 0, j = 0;
	
	while (i < strlen(p1) && j < strlen(p2))
	{
		if (p1[i] == p2[j])
		{
			j++;
			i++;
		}
		else
		{
			j = nextval[j];
			if (j == -1)
			{
				i++;
				j++;
			}
		}
	}
	if (j == strlen(p2))
	{
		answer = i - strlen(p2)+1;
	}
	
	cout << "第" << answer<<"个字符,开始";
	cout << endl;
	for (int i = 0; i < strlen(p2); i++)
	{
		cout << p1[answer - 1 + i];
	}
	
}

运行结果:

image-20221020182059842

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sleepymonstergod

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

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

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

打赏作者

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

抵扣说明:

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

余额充值