码迷,mamicode.com
首页 > 编程语言 > 详细

KMP算法初步理解

时间:2015-01-20 10:29:13      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:算法   algorithm   c++   

看了两天KMP算法,不知道理解的对不,初步理解总结如下:(主要是各种next数组把自己整晕了,有彻底懂的大神们再给指导下)

首先是思路,“字符串匹配的KMP算法_知识库_博客园”http://kb.cnblogs.com/page/176818/,问题的关键落在求数组上,而求数组实际是对自身求匹配度,所以求next数组的子函数和主函数很类似,所以网上讨论的好像主要是两种next数组,最好把相应的主函数列出来,还有像第二种的next和nextval数组都可用,在主函数相同的情况下,弥补一些缺陷

1.
 π数组指的是模式P的前缀函数,算法导论(原书第三版)P589,
eg:
   i :                1 2 3 4 5 6 7
P[i]:               a b a b a c a
π[i]:               0 0 1 2 3 0 1
计算方法可以这么算,看其前缀与后缀的最长重合长度(前缀:从第一个字符除最后一个,如aba的前缀a,ab,)
如: aba,     前缀a 和后缀a相等 所以为1
        abab    前ab 和后ab,所以为2

假设有一个文本T,要匹配的为P(ababaca)
到达T的某个位置,如下
            b a c b a b a b a a bc
                        a b a b a  c a
以某次匹配到P[5] 的 ababa为例,对应的π[5] = 3,所以下一次(next)比较,P[5]对应的T位置(即红a)对应i = 3对应的P[3],(P不动的话相当于T回走了,T不动的话就是P右移了),
    b a c b a b a b a a b c
                       a b a b a  c a
其对应的π[3]为1, 再下一次比较 红a对应i =1对应的P[1], 
  b a c b a b a b a a b c
                           a b a b a  c a
再下次P[5]对应的0了,综合来看,ababa根据π求出其对应的数组移动,可以不用挨个移动,提高效率,又不遗漏可能的匹配,
    这个到底是不是next数组啊,有的叫,有的叫覆盖函数,然后有下面那种next数组(主体程序不一样?反正我觉得算法导论上这个挺简单,好理解)。
对应的主体函数部分是:

 int i;

 int j = -1;

 const int m = strlen(pattern);

 next[0] = j;

 for (i = 1; i < m; i++)

 {

  while (j > -1 && pattern[j + 1] != pattern[i]) j = next[j];

  if (pattern[i] == pattern[j + 1]) j++;

  next[i] = j;   

 }



2.
另一种next数组,然后这个还有个nextval,在这个下,二者可以混着用,二者差别是nextval弥补了next在某些情况下的缺陷
主体函数是:

      int j=0,k=-1;

      next[0]=-1;

      while(j < strlen(t) - 1)

        {

             if(k == -1||t[j] == t[k])

                    {

                          j++;k++;

                          next[j]=k;

                     }

             else

                    k=next[k];

        }


至于求next和nextval,就是下面的讨论了,下面的T是指匹配的长度字符串,比如说上面的ababa就返回相应的next
(这块参考哪个大神的,又忘了,sorry,主要说是手动计算时方法)
T :            1 2 3 4 5 6 7
串 :           a b c a b a a
next:         0 1 1 1 2 3 2
nextval:      0 1 1 0 1 3 2
以上面的为例,先说next。next值本身的含义即是当进行匹配的模式串发生失配后,失配的这一字符再次进行匹配时要与哪个字符再进行比较?我们可以理解为这次配不上,那我下次和谁比?这样,next的值就与T发生了关系,表示了字符的比较位置。T就是元素的位置。
开始不用说,a前面没有,就是0,b要和a比,a的位置是1,b就是1。简单说,开头两个肯定是0,1!
第三个,c,c的前面是b,bc无法与开头的a比,所以c还是要单独找位于1的a,所以它也是1。
第四个,a,和第三个c一样,没有可以满足ca的字符串,最后a只能自己和第一个a配,它也是1。
第五个,b,看b前面,正好,a可以与开头的a对上,而第五个b正好在2的位置,所以b就是2。
第六个,a,看a前面,发现,a前面的ab可以与开头的ab对上,对上后,第六个a在位置3,所以就是3。
第七个,a,看a前面,只有a能够与开头配上,而“baa”则不行,所以它只有为2。
由此可以看出,next的计算,实际上就是计算当前字符以及当前字符前面的字符与开头匹配成功后,当前字符的最终位置,如果不成,就只能单独找第1个,所以它的值只能为1。
再看nextval,nextval是建立在next的基础上,我自己是这样理解的:同样是匹配,如果匹配成功,则位于后面的字符的next继承匹配成功的字符的nextval值,如果不成,保持不变。
以上为例:
第二位置的b按next值与开头a比较,不符,nextval不变,为1。
第三位置的c同样与1位置的a比较,不同,不变还是为1。
第四位置的a按next值与开头a比较,相同,继承开头a的nextval值,0。
第五位置的b按next值与二位置的b比较,相同,继承b的nextval值,1。
第六位置的a按next值与三位置c比较,不同,保持不变,3。
第七位置的a按next值与二位置b比较,不同,保持不变,2。
以上就是我的理解,当然,这是完全抛开了算法的描述,按照单纯计算next&nextval的值。关于算法,还是要好好理解的。
下面给出一个长的,加深印象。
            123456789……
            abcaabbabcabaacbacba
next:     01112231234532211211
nextval: 01102130110532210210

KMP算法初步理解

标签:算法   algorithm   c++   

原文地址:http://blog.csdn.net/u013016027/article/details/42914213

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!