数据结构学习笔记(一)——字符串的模式匹配

参考:
北京大学数据结构与算法c++

模式匹配

已有一个目标字符串T,给定模式P,在目标字符串T中搜索与模式P全同的一个字串,并求出T中与P全同匹配的字串(“简称为配串”),并返回其首字符位置

例如:在字符串“hello world”中找到“llo”并返回2

朴素模式匹配

利用穷举法,逐个字符后移匹配,如果该次匹配失败,则需要首字符后移到上次首字符的下一个,在逐个字符进行匹配,时间复杂度大。即尝试所有的可能情况,包含多次冗余比较。

算法一

代码实现:

运行结果:
输出2

算法二

int FindPat_2(string T, string S, int startidx)
{
	int Lastidx = T.length() - S.length();
	int S_LEN = S.length();
	if (startidx > Lastidx)
		return -1;
	else
	{
		int i = startidx, j = 0;
		while (i < T.length() && j < S_LEN)
		{
			if (S[j] == T[i])
			{
				i++;
				j++;
			}
			else
			{
				i = i - j + 1;
				j = 0;
			}
			if (j >= S_LEN)
				return i - j;
		}
		return -1;
	}
}

运行结果:
输出2

效率分析

T长度为n,模式长度为m,m<=n
如果n的游标每一次移动进行比较匹配,则一共需要比较(n-m+1)次
每一次相同匹配所耗费的时间最坏情况下是m
因此整个算法的最坏时间开销估计为O(m*n)
在匹配中,包含很多冗余匹配,在上一次匹配中已经知道后移一位不满足条件,应该将其去除,减少比较次数。

无回溯匹配

暴力法进行匹配时,主串和模式串的指针i,j都需要进行回退,而主串的指针回退位数超过了合理范围,导致比较次数增加。对于一个给定的模式串,其中每个字符都有可能会遇到匹配失败,这时对应的 j 指针都需要回溯,具体回溯的位置其实还是由模式串本身来决定的,和主串没有关系。

next数组特征

模式串中具有一定的规律,该规律有效利用可以减小比较次数

串的前后缀

串的前缀:包含第一个字符,且不包含最后一个字符的子串
串的后缀:包含最后一个字符,且不包含第一个字符的子串
以ababab为例
其其中一个前缀为ababa,其中一个后缀为babab

计算方法是:对于模式串中的某一字符来说,提取它前面的字符串,分别从字符串的两端(前后缀)查看连续相同的字符串的个数(最长长度),在其基础上 +1 ,结果就是该字符对应的值。
每个模式串的第一个字符对应的值为 0 ,第二个字符对应的值为 1 。
字符串 “abcabac” 对应的 next 数组中的值为(0,1,1,1,2,3,2)
如模式串取到倒数第三个字符时匹配失败,则其前面的串为abca,然后比较前后缀,a和a、ab和ca、abc和bca只有一组且长度为1,然后在这个基础上再加上1则对应的next数组值为2。
详见参考
KMP算法(快速模式匹配算法)详解以及C语言实现

//next数组计算
void Next(string A, int* next) {
	next[0] = 0;
	int i = 0;
	int j = 0;
	while (i < A.length()) {
		if (j == 0 || A[j - 1] == A[i])
		{
			j++;
			i++;
			next[i] = j;
		}
		else
		{
			j = next[j - 1];
		}
		cout << "i: " << i << "  j: " << j << "  next:  " << next[j] << endl;
	}
}

KMP完整代码实现

KMP算法优化

KMP存在的问题

当主串与模式串中比较的字符不匹配时,模式串回溯到相应的next数组位置,如果此时回溯的字符与原先字符相同,那么新一次的比较也是失效的,多进行了一次无意义的比较。
如模式串aaaab与主串aaacaaaabxxxx进行匹配时,当主串匹配到c时,对应的模式串字符为a,模式串需要根据next数组进行回溯
结果计算aaaab的next数组为0,1,2,3,4;
则应该回溯到第三个字符也就是a,同时a又匹配失败,继续回溯到第二个字符也是a,最后回溯到第一个a,这种回溯是极其冗余的

KMP算法优化-nextval数组

模式串:a,a,a,a,b
next:0,1,2,3,4
nextval的值从左至右看
将相同的字符next值修改为与之前相同字符相同next的值
即:
0,0,0,0,4
例子:

posted @ 2022-04-13 09:55  LV426  阅读(109)  评论(0)    收藏  举报