数据结构——KMP算法、BF算法

BF算法:

BF算法的实现思想:我们可以定义两个索引值i和j,分别指示主串str和子串sub当前正待比较的字符位置,从主串str的第pos个字符起和子串sub的第一个字符比较,若相等,则i++,j++,否则从主串str回到上次匹配开始的下一个位置即i-j+1,子串回到0号位置,重复执行,直到子串sub中的每个字符依次和主串str中的一个连续字符串相等,则匹配成功,函数返回该连续字符串的第一个字符在主串str中的位置,否则匹配不成功,函数返回-1

代码实现:

int BF(const char *str,const char *sub,int pos)//pos为主串位置
{
	assert(str != NULL&& sub!=NULL);
	int i = pos;
	int j = 0;
	int lens = strlen(str);
	int lensub = strlen(sub);
	while (j < lensub&&i < lens)
	{
		if (str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;//匹配失败时,i回到上次匹配开始的下一个位置
			j = 0;
		}
	}
	if (j >= lensub)
	{
		return i - j;
	}
	else
	{
		return -1;
	}
}

小结:

以上算法完全可以实现要求的功能 ,而且在字符重复概率不大的情况下,时间复杂度也不是很大,一般为O(Plen+Tlen)。但是一旦出现如下情况,时间复杂度便会很高,如:子串为“aaaaaaaab”,而主串为 “aaaaaaaaaaaaaaaaaaaaaaaaaab” ,由于子串的前8个字符全部为‘a’,而主串的的前面一大堆字符也都为a,这样每轮比较都在子串的最后一个字符处出现不等,因此每轮比较都是在子串的最后一个字符进行匹配前回溯,这种情况便是此算法比较时出现的最坏情况。因此该算法在最坏情况下的时间复杂度为O(Plen*Tlen),另外该算法的空间复杂度为O(1)

KMP算法:

KMP算法的实现思想: BF算法的时间复杂度之所以大,是由于索引指针的回溯引起的,针对以上不足,便有了KMP算法KMP算法可以在O(Plen+Tlen)的时间数量级上完成串的模式匹配操作。其改进之处在于:每一趟比较重出现字符不等时,不需要回溯索引指针i,而是利用已经得到的部分匹配的结果将子串向右滑动尽可能远的距离,继续进行比较。它的时间复杂度为O(Plen+Tlen),空间复杂度为O(Plen)。

在KMP算法中我们设计了一个next数组用来保存匹配失败后j回退的位置k,例:next[j] = k;next[0] = -1;next[1] = 0;那么next数组里的内容如何计算呢?我们有以下规则:

找到相同的两个真子串长度即为k,必须是一个以0号下标开始,另一个以j-1下标结尾,如果这两个下标的真子串不相同,则k = 0;(真子串:不包含本身的子串)

图解:

数据结构——KMP算法、BF算法_第1张图片

然后我们做一些推理:假设当前next[j] = k那么next[j+1]的值是多少呢?请看以下图解:

数据结构——KMP算法、BF算法_第2张图片

假设i为当前位置的i,k为前一项的k,我们又可以做出以下推理:

数据结构——KMP算法、BF算法_第3张图片

基于以上推理我们可以推导出KMP算法代码:

//得到next数组
void GetNext(int *next, const char *sub)
{
	next[0] = -1;
	next[1] = 0;
	int i = 2;//当前的i
	int k = 0;//前一项的k
	int lensub = strlen(sub);
	while (i < lensub)
	{
		if (k== -1||sub[i-1] == sub[k])
		{
			next[i] = k + 1;
			i++;
			k = k + 1;
		}
		else
		{
			k = next[k];
		}
	}
}
int KMP(const char *str, const char *sub, int pos)
{
	int i = pos;
	int j = 0;
	int lens = strlen(str);
	int lensub = strlen(sub);
	int *next = (int *)malloc(sizeof(int)*lensub);
	assert(next != NULL);
	GetNext(next,sub);
	while (j < lensub&&i < lens)
	{
		if (j == -1||str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j >= lensub)
	{
		return i - j;
	}
	else
	{
		return -1;
	}
}

你可能感兴趣的:(原创,基础)