0
点赞
收藏
分享

微信扫一扫

基础数据结构:KMP算法

思考的鸿毛 2022-04-06 阅读 104

核心思想:i打死不回退

此时,发生了失配,然后通过观察可以得知,失配之前已经匹配成功的那些字符,存在两种情况:
1.互不相等的情况下,i就可以不用回退(i就算回退了,也肯定会失败)

       上述说道,如果发生失配时,失配前的字符串互不相等,i可以不用回退
如果发生失配时,失配前的字符串互有相等情况,i可能需要向前回退,之不过,我们只要证明左绿那条线和上橙那条线相等,那么i也就可以不用回退,而是让j不再回退到0,而是回退到一个合适的位置,去代替掉
现在重点就在:需要去证明左绿和上橙相等
(因为偶橙色上下两条线铁定相等,那么我们只需要关注子串即可,证明左绿和右绿存在即可)
(证明左绿和上橙相等可以用证明左绿和右绿相等代替掉)
KMP:1.i打死不回退   2.模式匹配串只和子串有关

 

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>

//求子串的模式匹配串next
int *Get_Next(const char *sub)
{
	assert(sub != NULL);
	int len = strlen(sub);
	int *next = (int*)malloc(len * sizeof(int));
	assert(next != NULL);

	next[0] = -1;
	next[1] = 0;

	int j = 1;//通过已知推位置  j代表已知位置  j+1代表要推的未知位置
	int k = next[1];
	while(j+1 < len)
	{   
		if(k==-1 || sub[j] == sub[k])//如果当前字符和回退的字符相等 将k+1赋值给下一个位置
		{                              //或者k==-1,触底了,也是将k+1赋值给下一个位置
			k++;
			j++;
			next[j] = k;
		}
		else
		{
			k = next[k];
		}
	}

	return next;
}

//KMP算法的主串,由于i打死不回退,只会遍历一遍 整体时间复杂度O(n+m)
int KMP_Search(const char *str, const char *sub, int pos)
{
	assert(str!=NULL && sub!=NULL && pos>=0 && pos<strlen(str));

	int i = pos;
	int j = 0;
	int len_str = strlen(str);//len_str保存主串有效长度
	int len_sub = strlen(sub);//len_sub保存子串有效长度

	int *next = Get_Next(sub);//此时,子串的模式匹配串获取到

	while(i<len_str && j<len_sub)
	{
		if(j==-1 ||str[i] == sub[j])//j如果在第一个字符就失配,这时,只能让i向后走一步i++,j应该指向开始位置(0),但是j现在值是-1,要变成0需要j++
		{                           //或者i和j指向的字符相等也是i++,j++   
			i++;
			j++;
		}
		else
		{         
			//kmp要求i打死不同回退,j回退到一个合适的位置
			j = next[j];
			//i = i-j+1;  //i回退到这一趟开始位置,的下一个位置继续去比较
			//j = 0;     //j回退到0    
		}
	}
	//此时,当while退出,肯定要么找到,要么没找到,只需要通过j判断即可
	if(j < len_sub)//j没有走出自身边界,则没找到
	{
		return -1;
	}
	else
	{
		return i-j;
	}
}

int main()
{
	const char *str = "ababcabcdabcde";
	const char *sub = "abcd";

	int tmp = KMP_Search(str, sub, 7);
	if(tmp >=0 )
	{
		printf("找到了,开始下标为%d\n", tmp);
	}
	else
	{
		printf("没有找到\n");
	}
	return 0;
}

 运行结果:

 

 

 

举报

相关推荐

0 条评论