经典算法——KMP模式匹配

       对于一个串中某个子串的定位操作称为串的模式匹配,其中待定的子串称为模式串。算法的基本思想:从主串的第一个位置起和模式串的第一个字符开始比较,如果想等,则继续逐一比较后续字符;否则从主串的第二个字符开始,在重新用上一步的方法与模式串中的字符比较,以此类推,知道比较完模式串的所有字符。若匹配成功,则返回模式串在主串中的位置;若匹配不成功,则返回一个可区别与主串所有位置的标记,如“-1”,这是最简单的模式匹配,暴力枚举。

       上面是一个简单的模式匹配,优点是容易理解,实现简单;缺点也很明显:效率不高。

       从简单模式匹配算法可以看两点重要信息:1.标记i在主串中的位置基本反映了算法完成的进度,i走的越快,或者说i回溯的距离越小,算法执行就越快。2.通过i和j的回溯,是的下一趟尽可能消除当前位置的不匹配,进而使i继续往前走。由此,容易看出提升效率的一个可能的突破点:不回溯i,想办法通过调整j的位置消除i的不匹配。

      定义一个整型数组next[],next[n]中保存了模式串下标n处发生不匹配时,主串应当从模式串下标k处的字符开始比较,即next[n] = k;

      由于最近比较忙,对于具体算法推导就先不写了,有空会补齐,整个推导的过程。

     下面是KMP的一个简单实现,虽然求解next数组的方法不是一种高效的方法,但却更便于手工推导。

#include 
#include 

int  KMP(char str[], char subStr[], int next[])
{
	int i = 0, j = 0;
	while(i < strlen(str) && j < strlen(subStr))
	{
		if(str[i] == subStr[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
			if(j == -1)
			{
				j = 0;
				++i;
			}
		}
	}
	if(j == strlen(subStr))
		return i - strlen(subStr);
	else
		return -1;
}

void getNext(char subStr[], int next[])
{
	int i = 0, j = -1;
	next[0] = j;
	while(i < strlen(subStr))
	{
		if(j == -1 || subStr[i] == subStr[j])
		{
			++i;
			++j;
			next[i] = j;
		}
		else
			j = next[j];
	}
}

int main()
{
	char str[100], subStr[50];
	int next[50] = {0};
	scanf("%s", str);   ///主串 
	scanf("%s", subStr);     ///模式串 
	getNext(subStr, next);
	
	for(int i=0; i < strlen(subStr); i++) ///输出next数组的值 
	{
		printf("%d   ", next[i]);
	}
	printf("\n");
	
	int pos = KMP(str, subStr, next);
	printf("%d\n", pos);
	return 0;
}


你可能感兴趣的:(经典算法,数据结构)