KMP算法了解一下

参考:https://blog.csdn.net/v_july_v/article/details/7041827(看懂这个博文基本就懂了)

问题引入:已经文本串S---“BBC ABCDAB ABCDABCDABDE”,模式串P---“ABCDABD”请找出P在S中出现的位置。(S[15])

也就是在字符串中找到子串第一次出现的位置。

朴素算法:

int ViolentMatch(char* s, char* p)
{
	int sLen = strlen(s);
	int pLen = strlen(p);
 
	int i = 0;
	int j = 0;
	int res=0;
	for(i=0;i<sLen-pLen;i++)
	{
		if(s[i]==p[0])
		{
			for(j=0;j<pLen;j++)
				if(s[i+j]!=p[j])
					break;
			if(j==pLen)
				{
					res=1;
					 break;
				}	
		}
	}
	if(res)
	{
		printf("find!%d\n",i);
		return i;
	}
	else
		printf("NO\n");
}

浅显易懂,S从0到尾-尾 逐个排查,一旦第一个字符匹配那就进如第二轮排查,也就是到P中从0到尾 如果完全一致那就找到了。

问题1:两重循环效率不高,复制读是两个字符串长度的乘积。

问题2:S字符串是非常严谨的一个一个来的。

++++++++++++++++++插播一个错误 不要看++++++++++

现在我写一个引子算法,它是有逻辑问题的,一起看下:

int KmpSearch(char* s, char* p)
{
	int i = 0;
	int j = 0;
	int sLen = strlen(s);
	int pLen = strlen(p);
	printf("strlens--%d strlenp--%d\n",sLen,pLen);
	while (i < sLen && j < pLen)
	{ 
		if (s[i] == p[j])
		{
			i++;
			j++;
		}
		else
		{   
			i++;
			j=0;
		}
	    printf("%d---%d---\n",i,j);//发现问题!逻辑bug
	}

	if (j == pLen)
	{
		printf("find!%d\n",i-j);
		return i - j;
	}
	else
	{
		printf("NOfind!\n");
		return -1;
	}
}

    问题来了,效果是找不到!用一重循环没有覆盖完全!也就是else里面怎么写呢?

bug是前面匹配相等,然后一个字符不在相等,调到了else此时j可以清退回到0头部,而i呢?其实i很尴尬,第一你希望在不匹配的时候它可以++使得有机会进如到if,第二如这个bug你又希望此时i回到当初的地方+1

+++++++++++++++++++广告结束++++++++++++++++

KMP的做法是:两重循环改为1重!S字符串不要每次都+1,而是只许前进不许后退。比如上面的例子,




此时会失配!只许前进不许后退的意思是现在S不是想以前一样步进一步,(那样的话就是其实已经走到了空格现在退回到B)


KMP做法是S你就不动了,我动P。


这个P往右移动了4位,4是怎么来的?这就是理论了。

void GetNext(char* p,int next[])
{
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1;
	int j = 0;
	while (j < pLen - 1)
	{
		//p[k]表示前缀,p[j]表示后缀
		if (k == -1 || p[j] == p[k]) 
		{
			++k;
			++j;
			next[j] = k;
		}
		else 
		{
			k = next[k];
		}
	}
}

-1 0 0 0 0 1 2

也就是P---“ABCDABD”第几个失配就是那个数

int KmpSearch2(char* s, char* p)
{
	int i = 0;
	int j = 0;
	int sLen = strlen(s);
	int pLen = strlen(p);
	while (i < sLen && j < pLen)
	{
		//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++    
		if (j == -1 || s[i] == p[j])
		{
			i++;
			j++;
		}
		else
		{
			//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]    
			//next[j]即为j所对应的next值      
			j = next[j];//-1	0	0	0	0	1	2
		}
	}
	if (j == pLen)
		printf("%d\n",i-j);
		//return i - j;
	else
		//return -1;
		printf("NO\n");
}


现在就是理论了 数组怎么来的 


猜你喜欢

转载自blog.csdn.net/weixin_42381351/article/details/80966649