数据结构学习笔记-从头开始理解KMP算法(2)

来源:互联网 发布:网络弊大于利辩论词 编辑:程序博客网 时间:2024/05/22 00:05

      上文说到KMP算法提供了一种充分利用已匹配字符和模式串本身信息的方法,本文将探究KMP算法具体是如何实现这样一种改进的。

二 KMP算法思想

    在每一趟匹配过程中,若出现字符不等,BF算法会把指向主串的指针i回溯到这一趟匹配开始时i所处位置的下一个位置i-(j-1)+1,模式串的指针j指向模式串的开头处,开始下一趟匹配。与BF算法不同,在处理出现字符不等的情况时,KMP算法会将模式串的指针j移到一个‘合适’的位置,主串指针i不变,继续接下来的匹配。什么是‘合适’的位置呢?一图以蔽之,


在S[i]不等于P[j]时,图中的next[j]所指向的位置即为图示情况下模式串指针j的新的合适的位置。那么next[j]满足什么样的条件呢?

在模式串P中,若存在t满足字符序列p[1]p[2]...p[t-1]=p[j-t+1]p[j-t+2]...p[j-1],那么next[j]的值为满足该条件的t的取值集合中的最大值(1<t<j)

结合KMP算法的执行过程和图例,我们来探究一下其中的妙处。

在图中,模式串j位置处的字符与主串i位置处的字符不一致,这是在这一趟匹配过程中首次出现字符不一致的情况,那么j位置之前,主串的字符与模式串的字符肯定是对应相等的。所以字符序列p[1]...p[j-1]=s[i-j+1]...s[i-1]。又根据next[j]所满足的的条件,则会有字符序列p[1]...p[next[j]-1]=p[j-next[j]+1]...p[j-1].综上,字符序列p[1]...p[next[j]-1]=s[i-next[j]+1]...s[i-1]。那么在下一趟匹配时,我们可以从模式串的next[j]位置开始与主串的i位置字符比较,next[j]位置之前的字符序列已经与主串i位置之前的对应长度的字符序列匹配成功了。这样做的好处有:主串的指针i将不需要回溯,省去了对模式串中已匹配的字符的重复比较。文章开头处的疑问可以在此处得到解答--next[j]的取值利用了模式串本身的信息,已匹配的字符决定当前j的值,当前p[j]与s[i]的比较结果将影响接下来的匹配过程。

在对KMP算法的学习过程中,我发现主要的疑点和难点就在于next[j]取值的意义的理解、与BF算法比较,KMP算法匹配过程的不同以及优势之处。接下来是我的一些理解。对于next[j],首先要注意到它是针对模式串P的,与主串无关。在与主串进行匹配之前,我们就可以预先处理得到不同j的next[j]取值。接下来,我们可以在对next[j]取值意义理解的基础上找到求next[j]值的方法。在模式串中,求next[j]意味着---在模式串的j位置的字符与主串中对应的字符不相等,那我们尝试在模式串中找这样一个字符序列:

  1. 紧挨着p[j],即在模式串中,该字符序列的下一个字符就是p[j]。
  2. 将它与模式串的字符从头开始比较,直到它的末尾结束,每个字符都对应相等。
  3. 它越长越好,这样我们就可以省去更多的与主串字符比较的操作。

符合条件的字符序列的长度值+1即为满足要求的next[j]。这样在模式串j位置之前和next[j]位置之前就有一段相同的字符序列。

当 j=1时,求next[j]意味着模式串第一个字符即和主串对应字符不等,那么从主串的该字符位置开始,我们肯定找不到与模式串匹配的字符序列,应该忽略掉主串中的该字符,尝试从主串中的下一个字符开始匹配。令next[1]=0,代表该对主串执行指针i后移的操作。

当j>1时,若模式串中不存在满足上述条件的字符序列,则next[j]=0+1=1。