关于KMP算法next数组的改进 您所在的位置:网站首页 如何计算next函数值 关于KMP算法next数组的改进

关于KMP算法next数组的改进

2024-06-25 15:03| 来源: 网络整理| 查看: 265

写在最前:

KMP算法的核心思路:

问题由模式串决定,而不是由目标串决定!

此文前提是已掌握next数组算法!

问题引入:

假设模式串及其next数组:

模式串开始与目标串匹配:

模式串位置4与目标串位置4不匹配,所以下一步模式串指针应该按照next[4]移动:

但我们发现,这没有丝毫意义,刚刚就是因为模式串‘B’与目标串‘C’不匹配导致我们按照数组next调整指针位置,但调整后的指针所在位置模式串元素仍为’B’,自然仍不匹配,还要继续按照数组next回溯指针。

但是我们可不可以改进next数组来避免做类似无用功呢?

分析与解决:

于是诞生了nextval数组,同样的,我们假设模式串为:

                    

**与next数组一致,如果位置1元素即不匹配,该位置nextval数组值为0**

(不是本文重要因素,故原因略去)

紧接着,假如位置1元素已匹配,位置2元素不匹配,按照位置2所对应的next数组值我们应回溯至位置1,但是我们发现位置1与位置2元素一样,所以说回溯之后仍是相同元素(非同一个)在与目标串比较,显然仍不匹配,就会继续回溯到位置1所对应的next数组值即0。

按照这个原理,我们设模式串的指针为k:

情况一:

特别地,我们发现位置1与位置2元素相同,在位置2不匹配(此时k=2)时我们按照next[2]=1,k回溯至位置1,像上文位置1元素与位置2元素相同,用模式串的位置1元素继续比较无意义,继续按照next[1]=0回溯指针,指针已到头,回溯结束,因此,我们记位置2对应的nextval数组值为0,此时next[2]=1而nextval[2]=0,两数组值不同。(记住这种情况的回溯过程,后文会引用)

情况二:

继续向下移动指针k,假设k移动到位置3,k之前元素已匹配,而k此时所指元素不匹配,那我们就指针回溯,按照位置3所对应的next数组值我们应回溯至位置2,这时我们发现情况和上述有所区别,位置2与位置3元素不相同,所以回溯后可能匹配成功(此时k=2),所以我们记位置3对应的nextval数组值为2,即nextval[3]=2=next[3],发现此时该位置next数组值与nextval数组值相同。

那何时next数组值与nextval数组值相同?又何时不同呢?

我们发现:当在k位置不匹配时,如果k位置所对元素与next[k]位置所对元素相同时,它们两数组值不同;而如果k位置所对元素与next[k]位置所对元素不相同时,它们两数组值相同。

好,现在我们发现了这个规律,接着上面的情况,继续让k指针向下移动,k移动到位置4(之前元素已匹配),假设此时不匹配,指针回溯到next[4]=1,而位置1元素与位置4元素相同,继续回溯next[1]=0,所以位置4所对nextval数组值为0(nextval[4]=0),与next[4]=1不同,符合上述发现。

乘胜追击,继续让k指针向下移动,k移动到位置5,假设此时不匹配,指针回溯到next[5]=2,而位置2元素与位置5元素相同,继续回溯next[2]=1,位置1元素与位置5元素仍相同,继续回溯next[1]=0所以位置5所对nextval数组值为0(nextval[5]=0),与next[5]=2不同,符合上述发现。

但是,“乘胜追击”的情况指针k都不止回溯了一次,两次的回溯出现了两次的元素相同,在指针从2回溯到1回溯到最终的0的操作,实际上也就是当k=2(上文情况一)时指针最终回溯至nextval[2]=0,所以说我们可以直接利用之前(并不一定是上一次)操作得出的nextval数组值来简化重复的操作。也就是说,如果位置k的元素与next[k]元素相同时,nextval[k]=nextval[next[k]]。

现在,我们已经验证并完善了“发现”关于“如果k位置所对元素与next[k]位置所对元素相同时,它们两数组值不同”,接着我们验证另一部分“如果k位置所对元素与next[k]位置所对元素不相同时,它们两数组值相同。”

继续下移指针k至位置7,假设之前元素已匹配,位置7此时不匹配,指针回溯至next[7]=4,位置4元素与位置7元素不同,此时位置4元素可能与目标串匹配成功,故nextval[7]=4,即nextval[7]=next[7]=4,太棒啦,“发现”的另一部分也被验证正确了。

结论:

如果位置k的元素与next[k]元素相同时,nextval[k]=nextval[next[k]]

如果位置k的元素与next[k]元素不同时,nextval[k]= next[k]

代码实现: /*CaptainUniverse_ 2022.4.14*/ void get_nextval(String T,int *nextval)//T为模式串 { j=0;//前缀 i=1;//后缀 nextval[1]=0; while(i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有