KMP模式匹配算法

//朴素的模式匹配算法
//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回0.
//T非空,1 <= pos <= StrLength(S)。
int Index(String S,String T,int pos)
{
	int i = pos;//i用于主串S中当前位置下标,若pos不为1,则从pos位置开始匹配
	int j = 1;//j用于子串T中当前位置下标值
	while(i <= S[0] && j <= T[0])//若i小于S长度且j小于T的长度时循环
	{
		if(S[i] == T[j])//两字母相等时则继续
		{
			++i;
			++j;
		}
		else//指针后退重新开始匹配
		{
			i = i - j + 2;//i退回到上次匹配首位的下一位,至于为什么是这个,可以举个例子有助于理解
			j = 1;
		}
	}
	if(j > T[0])
		return i - T[0];
	else
		return 0;
}

分析一下朴素模式匹配算法的时间复杂度:

(n为主串S的长度,m为要匹配的子串T的长度)

1)最好情况下,就是一开始就匹配成功,时间复杂度为O(1),稍差一些就是开始每次都是首字母不匹配,比如S = "abcdefgoogle",T = "google",此时的时间复杂度为O(n + m);

2)根据等概率原则,平均是(n + m) / 2次查找,时间复杂度为O(n + m);

3)最坏情况下的时间复杂度,观察图5-6-6和图5-6-7,可知为O((n - m + 1) * m);



朴素模式匹配算法比较低效,后来发明了KMP模式匹配算法(克努特--莫里斯--普拉特算法)。

在KMP模式匹配算法中,不用回溯i的值,所以将算法的时间复杂度从O((n - m + 1) * m)砍到了O(n + m)。

在引入KMP算法时,先引入一个例子:S = "abcdefgab",T = "abcdex";图5-7-1是用朴素模式匹配算法的过程,因为T中a与后面的字母都不一样,在第一次比较中,bcde与主串S中的bcde进行匹配过了,类似传递性,所以a与主串S的那几个位置的匹配可以不做,从而减少时间,图中的2,3,4,5都可以省去。

KMP模式匹配算法避免了没有必要的回溯的发生。

i值不进行回溯了,那就要考虑j值的变化,T串各个位置的j值的变化定义为一个数组next,那么next的长度就是T串的长度。于是我们得到下面函数的定义:

(CSDN的编译器好像打不出来上面的样子,只好截图)

//通过计算返回子串T的next数组。
void get_next(String T,int *next)
{
	int i,j;
	i = 1;
	j = 0;
	next[1] = 0;
	while(i < T[0])//此处T[0]表示串T的长度
	{
		if(j == 0||T[i] == T[j])//T[i]表示后缀的单个字符;T[j]表示前缀的单个字符
		{
			++i;
			++j;
			next[i] = j;
		}
		else 
			j = next[j];//若字符不同则j值回溯
	}
}


//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0.
//T非空,1 <= pos <= StrLenth(S).
int Index_KMP(String S,String T,int pos)
{
	int i = pos;
	int j = 1;

	int next[255];
	get_next(T,next);

	while(i <= S[0] && j <= T[0])
	{
		if(j == 0||S[i] == T[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];//j退回合适的位置,i值不变
		} 
	}
	if(j > T[0])
		return i - T[0];
	else
		return 0;
}

KMP还是有缺陷的,比如当S = "aaaabcde",T = "aaaaax"
KMP模式匹配算法的改进

具体过程参考《大话数据结构》P168

//求模式串T的next函数修正值并存入数组nextval
void get_nextval(String T,int *nextval)
{
	int i,j;
	i = 1;
	j = 0
	nextval[1] = 0;
	while(i < T[0])
	{
		if(j == 0 || T[i] == T[j])
		{
			++i;
			++j;
			if(T[i] != T[j])
				nextval[i] = j;
			else
				nextval[i] = nextval[j];
		}
		else
			j = nextval[j];//若字符不同,则j值回溯
	}
}



彻底理解KMP模式匹配算法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值