KMP算法详解

算法简述:

KMP算法是将字符串匹配过程中的信息运用起来实现每一次匹配过程主数据不回退例如:

主数据:A :  abccdbbdhjbabcabcdga

匹配字符串:  B:abcabcd

以第一次匹配为例:当主数据匹配到’c‘时不再适配此时匹配字符串中已经匹配的字符为“abca”此时可以得到主数据中第一次匹配字符后二个字符为’b‘’c‘所以我们可以运用这一信息从而避免在失配后主数据退回’b'重新比较,以此达到降低时间复杂度的目的。

信息运用:

观察数据“abca”可以发现真正有用的信息是“bc”即匹配字符失配位置以前除去第一个字符为有效字符(也就是主数据中需要重新比较的字符)所以我们可以以匹配字符串的回退代替主数据回退。为达到这一目的我们引入了next数组以记录匹配字符串每个位置失配后匹配位置需要回退的位置以代替主数据回退。

next数组求法

next数组第一个数字为-1(触底标志)第二个为0。求第n个位置next数组值则比较匹配字符串第n-1个位置B[n-2]与第n-1个位置对应的next[n-2]所对应位置的匹配字符串字符B[next[n-2]]是否相等若相等next[n-1]=next[n-2]+1否则就继续和B[next[next[n-2]]]比较若触底则next[n-1]=0

注:next数组写法形式有多种、

代码实现:

int* Get_Next(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
	int len = strlen(brr);//next数组长度
	int* next = (int*)malloc(len * sizeof(int));
	next[0] = -1;//设置触底标志
	if (len > 1)//防止brr数组只有一个值
		next[1] = 0;
	int i = 1;//代表brr位置
	int j = 0;//要比较的next数组位置
	while (i < len - 1)//求next数组
	{
		if (j==-1||brr[i] == brr[j])
		{
			i++;
			j++;
			next[i] = j;
		}
		else
		{
			j = next[j];//匹配字符串回退
		}
	}
	return next;
}
bool KMP(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
	int* next = Get_Next(arr, brr);
	int i = 0;
	int j = 0;
	int len1 = strlen(arr);
	int len2 = strlen(brr);
	while (i < len1 && j < len2)//进行匹配
	{
		if (arr[i] == brr[j]||j==-1)
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];//匹配字符串回退
		}
	}
	if (j == len2)//如果完全匹配
		return true;
	else
		return false;
}

next数组优化nextval数组:

 在next数组中若出现B为“aaaabb”这类情况其next数组值为“-1,0,1,2,3,0”当其在第五个位置发生失配时此时主数据还要和B[3],B[2],B[1]比较但是这些位置的值相同是比较结果也一样是完全可以省略的。

代码实现:

int* Get_Next(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
	int len = strlen(brr);//next数组长度
	int* nextval = (int*)malloc(len * sizeof(int));
	nextval[0] = -1;//设置触底标志
	if (len > 1)//防止brr数组只有一个值
		nextval[1] = 0;
	int i = 1;//代表brr位置
	int j = 0;//要比较的next数组位置
	while (i < len - 1)
	{
		if (j==-1||brr[i] == brr[j])
		{
			i++;
			j++;
			nextval[i] = j;
		}
		else
		{
			j = nextval[j];//匹配字符串回退
		}
	}
	for (int i = 1; i < len; i++)//nextval优化
	{
		if (brr[i] == brr[nextval[i]])
			nextval[i] = nextval[nextval[i]];
	}
	return nextval;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值