KMP算法总结

其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。

在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。

假设

主串:s: ‘s(1)  s(2)  s(3) ……s(n)’ ;  

模式串 :p: ‘p(1)  p(2)  p(3)…..p(m)’

继续

现在我们假设 主串第i个字符与模式串的第j(j<=m)个字符“失配”后,主串第i个字符与模式串的第k(k<j)个字符继续比较

此时,s(i)≠p(j),  有

主串:               S(1)……  s(i-j+1)…… s(i-1)   s(i) ………….
                                || (相配)   ||       ≠(失配)
匹配串:                        P(1) …….  p(j-1)   p(j) 

由此,我们得到关系式
          ‘p(1)  p(2)  p(3)…..p(j-1)’   =    ’ s(i-j+1)……s(i-1)’

由于s(i)≠p(j),接下来s(i)将与p(k)继续比较,则模式串中的前(k-1)个字符的子串必须满足下列关系式,并且不可能存在  k’>k  满足下列关系式:(k<j),
          ‘p(1)  p(2)  p(3)…..p(k-1)’   =    ’ s(i-k+1)s(i-k+2)……s(i-1)’

即:

主串:        S(1)……s(i-k +1) s(i-k +2) ……s(i-1)     s(i) ………….
                        || (相配)  ||           ||       ?(有待比较)
匹配串:                P(1)      p(2)    …… p(k-1)    p(k)

现在我们把前面总结的关系综合一下

有:

 S(1)…s(i-j +1)…  s(i-k +1) s(i-k +2)  ……    s(i-1)     s(i) ……
           || (相配)  ||         ||               ||         ≠(失配)
           P(1) ……p(j-k+1)   p(j-k+2)  …....   p(j-1)    p(j) 
                      || (相配)  ||               ||          ?(有待比较)
                      P(1)       p(2)    …….    p(k-1)      p(k)

由上,我们得到关系:
‘p(1)  p(2)  p(3)…..p(k-1)’   =     ' p(j-k+1) p(j-k+2) p(j-k+3)……p(j-1)’

 

这样归结到了求next函数。

 

下面是next函数方法:

 1 void GetNext(char* t, int* next)
2 {
3 int i, j, len;
4 i = 0;
5 j = -1;
6 next[0] = -1;
7 while(t[i] != '\0')
8 {
9 if (j == -1 || t[i] == t[j])
10 {
11 i++;
12 j++;
13 next[i] = j;
14 }
15 else
16 {
17 j = next[j];
18 }
19 }
20 }

当一个字符串以0为起始下标时,next[i]可以描述为"不为自身的最大首尾重复子串长度"。

也就是说,从模式串T[0...i-1]的第一个字符开始截取一段长度为m(m < i-1)子串,再截取模式串T[0...i-1]的最后m个字符作为子串,如果这两个子串相等,则该串就是一个首尾重复子串。我们的目的就是要找出这个最大的m值。

详细实例见朱站立版《数据结构》例4-5。



posted @ 2012-02-13 19:28  logzh  阅读(261)  评论(0编辑  收藏  举报