对于KMP算法中next函数的一些解读

课本中的next函数如下:

​
void get_next(SString T,int next[])
{
	int i=1;
	next[1]=0;
	int j=0;
	while(i<T.length)
	{
		if(j==0||T.ch[i]==T.ch[j])
		{
			++i;
			++j;
			next[i]=j;
		}
		else j=next[j];
	}
}

​

T=aabaaa为例:

进入循环之前:i=1,j=0

进入循环之后:

第一趟:由于j==0,进入 if 语句i=2,j=1,next[2]=1

第二趟:由于T.ch[2](=a)==T.ch[1](=a) , i=3,j=2,next[3]=2

第三趟:由于T.ch[3](=b)!=T.ch[2](=a) , 进入else语句, 此时 j=next[2]=1

第四趟:由于T.ch[3](=b)!=T.ch[1](=a) , 进入else语句,此时 j=next[1]=0

第五趟:此时虽然T.ch[3](=b)!=T.ch[0],但是j==0,已然会进入if语句,此时i=4,j=1,next[4]=1

第六趟:此时T.ch[4](=a)==T.ch[1](=a),i=5,j=2,next[5]=2

第七趟:此时T.ch[5](=a)==T.ch[2](=a),i=6,j=3,next[6]=3

自此get_next函数结束,得到的next数组为:

j123456
Taabaaa
next[j]012123

不难发现i始终没有回溯,在第三趟时发现第三个字母与第二个字母不一样后,由j进行回溯,依次将第三个字母与第二个、第一个字母比对,在此过程中j回溯的方式由j=next[i]控制,这是因为此时next数组中next[1]已经有值且未进入循环之前已经定义了next[0]。此后有两种情况:

1)若前两个字母始终与第三个字母不一样,则会像上述一样由j=0再次进入if语句。

2)若前面有字母与第三个字母一样,这里我们假如第一个字母为b,则第四趟应为:T.ch[3](=b)==T.ch[1](=b),进入if语句,i=,j=2,next[4]=2

通过前面的分析可以看出来next函数的目的是寻找i指向字母之前的串的相同最大真前缀和最大真后缀+1的长度的值

j123456
Taabaaa
最大真前缀aaaa
next[j]012123

注:aabaa的真前缀有:a,aa,aab,aaba;真后缀有:a,aa,baa,abaa

为什么是最大真钱后缀的值加1?

因为当gif.latex?%5Cdpi%7B100%7D%20%5Cfn_jvn%20%22T_1T_2...T_%7Bk-1%7D%22%3D%22T_%7Bj-k&plus;1%7DT_%7Bj-k&plus;2%7D...T_%7Bj-1%7D%22时,其实就是在gif.latex?%5Cdpi%7B100%7D%20%5Cfn_jvn%20T_j个字母之前有相同的最大真前后缀,而其长度为k-1,所以要表示它之后的数就加1。

综上所述,next函数的本质为求相同最大真前后缀的值加1,其就为主串要移动的值,而在next函数中,T既是主串又是模式串。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值