KMP算法讲解

第一次写博客有点小激动,今天要讲一下KMP算法,这个查找算法比较难理解,我也是想了很久才想明白,我们在str2中的pos位置开始查找str1,当找到的时候返回str2中的下标,没有找到的时候返回-1;首先我们来参考一下我们最初写的查找字符串的函数,定义i=0为str2的下标,j=0为str1的下标,开始循环的时候,当遇到str2中的值,与str1中的值不同的时候,i变为最开始i前进的下一个下标,j的下标变为0,不断循环,知道i的值或者j的值大于他们的长度,然后再次判断,如果j的值大于str1的长度,则i-j的值,就是在str2中找到的str1的位置,在此函数中i需要不断地回退,因此时间复杂度比较大,在最大的时候会为O(n^2),因此我们用KMP算法的一个好处是i不需要回退,只需要把j回退到它该退的位置,j回退的位置,因此这样的时间复杂度较低,为O(m+n)首先我们需要在str1中查找两个相同的真子串,第一个真子串是str1的开头作为开头,第二个真子串是以刚刚匹配失败的前一个下标位置的作为结尾,每一次匹配失败的时候我们都需要去查找j该退回的位置,因此,定义一个数组来保存在每一个位置匹配失败的时候j应该回退的下标,下面的BF()是我们初次写的查找字符串的函数,Getnext()函数是我们获取一个next数组用来保存每一次j需要退回的位置,Getnextval()是根据得到的next再将j再次退到它直接应该回退的位置无论是利用Getnext()或者Getnextval()都能将j退回到该退的位置,然后从那个位置开始又与str2开始比较。
#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       

int BF(const char * str, const char *sub, int pos)
{
	assert(str != NULL&&sub != NULL);
	int lenA = strlen(str);
	int lenB = strlen(sub);
	if (pos<0 || pos>lenA)
	{
		return -1;
	}
	int i = pos;
	int j = 0;
	while (i < lenA&&j < lenB)
	{
		if (str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (j >= lenB)
	{
		return i - j;
	}
	else
	{
		return -1;
	}
}

static void Getnext(char *next, const char *sub)
{
	assert(next != NULL&&sub != NULL);
	int len = strlen(sub);
	if (len < 0)
	{
		return;
	}
	next[0] = -1;
	next[1] = 0;
	int j = 1;
	int k = 0;
	while (j < len-1)  
	{
		if (k==-1||sub[j] == sub[k])
		{
			next[++j] =++k;
		}
		else
		{
			k = next[k];
		}
	}

}

static void Getnextval(char *next, const char *sub)
{
	assert(next != NULL&&sub != NULL);
	int len = strlen(sub);
	if (len < 0)
	{
		return;
	}
	next[0] = -1;
	next[1] = 0;
	int j = 1;  //sub的下标
	int k = 0;
	while (j < len - 1)
	{
		if (k==-1||sub[j] == sub[k])
		{
			++k;
			++j;
			if (sub[j] == sub[k])
			{
				next[j] = next[k];
			}
			else
			{
				next[j] = k;

			}
		}
		else
		{
			k = next[k];
			if (sub[k] == sub[j])
			{
				next[j] = next[k];
			}
		}
	}
}

int KMP(const char *str, const char *sub, int pos)
{
	assert(str != NULL&&sub != NULL);
	int lenA = strlen(str);
	int lenB = strlen(sub);
	if (pos<0 || pos>lenA)
	{
		return -1;
	}
	int i = pos;
	int j = 0;
	char * next = (char *)malloc(lenB * sizeof(char));
	Getnextval(next, sub);
	while (i< lenA && j < lenB)
	{
		if (j==-1||str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j >= lenB)
	{
		return i - j;
	}
	else
	{
		return -1;
	}
	free(next);
}
      
      
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值