串的模式匹配-----KMP算法与BF算法

1.手动推算KMP算法

KMP算法是BF算法升级版本
BF算法就是暴力搜索,一个一个的去匹配
在这里插入图片描述

主串指针所指向的字符:a
模式串指针指向的字符:c
此时不匹配:模式串指针指向开始位置,主串指针指向第二个位置****

在这里插入图片描述

当遇到如下这种情况时候:

在这里插入图片描述

太浪费时间了,每次模式串到达最后一个位置才知道匹配失败,并且每次都匹配到模式串的最后一个字符才知道,确实花费时间

所以从而引入KMP算法-----串的模式匹配
KMP算法-----求解next数组
KMP算法-----主串匹配模式串

求解next数组步骤
例:

在这里插入图片描述

刚开始初始化next数组,next[1] = 0,k = 0, j = 1
next数组值的计算:
k:记录前后缀匹配长度,并且不匹配时候,k = 1,表示没有一个匹配的,下限是0,到达0说明一个匹配的没有
j:遍历串的每一个字符位置

前后缀理解:
例如字符串 abcde
前缀:abcd
后缀:bcde

循环:
if 匹配成功 或者 回溯达到界限k = 0*:
当前next的值:k+1
else 匹配失败:
当前k的值:通过next数组回溯得到新的k

第一次:填写next[2]元素值,k = 0,j = 1, 由于k = 0,所以next[++j] = ++k, 也就是next[2] = 1
在这里插入图片描述

第二次:填写next[3]的值,k = 1, j = 2, 他的前面元素 a b,k = 1也就是数组元素a,j = 2也就是数组元素 b,a不等于b,不匹配,然后根据next数组回溯,得到新的k值,k = next[k] = next[1]得到0,由于k = 0,所以next[++j] = ++k,也就是next[3] = 1
在这里插入图片描述

第三次:填写next[4]的值,j= 3,k = 1,他前面的元素为 a b a, j = 3也就是数组元素a,k=1也就是数组元素a,a等于a,匹配成功,所以next[++j] = ++k,所以next[4] = 2
在这里插入图片描述

第四次: 填写next[5]的值,j = 4, k = 2,他的前面元素, a b a a,j = 4也就是数组元素a,k=2也就是数组元素b,a不等于b,通过next数组回溯,得到新的k值,k = next[2] = 1,此时继续比较,k = 1数组元素为a,j=4数组元素为a,此时a等于a,成立,next[++j] = ++k,next[5] = 2
在这里插入图片描述

第五次: 填写next[6]的值,j = 5, k = 2,他前面元素为a b a a b, j = 5数组元素是b,k=2数组元素是b,b等于b匹配,next[++j]=++k, next[6] = 3

在这里插入图片描述

最终next数组算完。
最终next数组算出来了,next[] = {0,1,1,2,2,3}, 下标从1开始

主串与模式串匹配
if匹配成功或者j = 0
i++,j++
else
通过next数组回溯得到新的j值

匹配成功:主串与模式串指针分别往后走
匹配失败:通过next数组回溯,重新定位模式串的位置,得到模式串新的位置与主串当前位置比较
注意:当一直失败,一直回溯,下限是0,就要主串位置+1,模式串+1
当一开始匹配失败,就要回溯,j = 0, 当j = 0,然后,i++,j++,此时走到主串当前位置后面一个位置去,模式串到达第一个位置,j = 1
示例:

在这里插入图片描述

第一趟时候,i = 2, j = 2,不匹配,通过next数组回溯,j = next[j] = next[2] = 1

在这里插入图片描述

第二趟时候,i = 2, j = 1,不匹配,通过next数组回溯,j = next[j] = next[1] = 0,当j等于0时候,i++,j++,得到主串到达下一个位置,模式串到达第一个位置,i = 3, j = 1

在这里插入图片描述

当i = 8,j = 6时候,此时不匹配,通过next数组回溯, j = next[j] = next[6] = 3, i不动,i还是8,j变成3

在这里插入图片描述

第四趟时候,正好可以吧模式串在主串中找到,结束,匹配完成,只需要4次就匹配成功

最终模式串在主串的12-6 = 6位置上

2.BF算法代码实现

//BF算法-----主串str1, 模式串str2
int BF(char str1[], char str2[])
{
	int i = 0, j = 0;
	while (str1[i] && str2[j])
	{
		if (str1[i] == str2[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
		count1++;
	}
	if (!str2[j])
		return (i - j + 1);
}

3.KMP算法代码实现

//KMP算法
int KMP(char str1[], char str2[])
{
	int next[100];
	int i = 0, j = 0;
	get_next(str2, next); //获得next数组
	while (str1[i] && str2[j])
	{
		if (j == 0 || str1[i] == str2[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
		count2++;
	}
	return i - j + 1;
}

3.1求解next数组

//求next数组     模式串str,  next数组---模式串回溯的位置
void get_next(char str[], int next[])
{
	//1.初始化next数组,初始化k和j
	next[0] = -1;
	int k = -1;
	int j = 0;

	//循环
	while (str[j])
	{
		if (k == -1 || str[k] == str[j])
		{
			k++;
			j++;
			next[j] = k;
		}
		else
			k = next[k];			
	}
}

最终两个算法测试比较
输入主串:aaaaaaaaaaaaaaac
输入模式串:aaaac
BF:60次
KMP:27次

输入主串:acabaabaabcacbc
输入模式串:abaabc
BF:18次
KMP:14次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值