KMP算法

字符串匹配 – KMP算法

KMP算法是由D. E. Knuth,J. H. Morris和V. R. Pratt提出来的一种字符串匹配改进算法,和BF算法相比,KMP算法的最大特点是主串指针不回溯,当匹配失败后,由之前比较所得的信息来决定模式串中的哪个字符和主串指针所指字符再比较。因此这个算法涉及到的主要问题就是求匹配失败之后,应该用模式串中哪个字符和主串指针所指字符再比较。

假设主字符串为S0 S1 S2 … Sn,模式串为P0 P1 P2 … Pm,匹配失败时,主串指针所指位置为Si,模式串指针所指位置为Pj。若接下来主串字符Si(i指针不回溯)应与模式串中第k(k < j)个字符继续比较,则模式串中前k-1个字符必须满足下列关系式1),且不可能存在更大的k' > k满足下列关系式1)。
1) P1 P2 … Pk-1 = Si-k+1 Si-k+2 … Si-1

而由之前的比较可以得到的匹配结果是:
2) Pj-k+1 Pj-k+2 … Pj-1 = Si-k+1 Si-k+2 … Si-1

因此,由式1)和2)可以推出:
3) P1 P2 … Pk-1 = Pj-k+1 Pj-k+2 … Pj-1

由式子3),可以很清楚的看到,位置k的确定和主字符串无关,只要在模式串中找到满足式子3)的两个子串(子串越大越好),就可以确定k的位置。

KMP算法如下:

  1. void get_next(SString T, int next[])
  2. {
  3.     int j = 0, k = -1;
  4.     next[0] = -1;
  5.    
  6.     while (j < T.Length - 1) {
  7.         if (k == -1 || T[j] == T[k]) {
  8.             j++;
  9.             k++;
  10.             next[j] = k;
  11.         } else {
  12.             k = next[k];
  13.         }
  14.     }
  15. }
  16.  
  17. int KMP(SString S, SString T)
  18. {
  19.     int next[MAX_SIZE], i = 0, j = 0;
  20.    
  21.     get_next(T, next);
  22.    
  23.     while (i < S.Length && j < T.Length) {
  24.         if (j == -1 || S[i] == T[j]) {
  25.             i++;
  26.             j++;
  27.         } else {
  28.             j = next[j];
  29.         }
  30.     }
  31.    
  32.     if (j >= T.Length)
  33.         return i - T.Length;
  34.     else
  35.         return -1;
  36. }

由于KMP算法有效的利用了之前比较所得的信息,主串指针不需要回溯。因此,和BF算法相比提高了模式匹配的效率,特别是在最坏的情况下。KMP算法的时间复杂度为O(n+m)。

 

 

若非注明,本博客文章均属原创,转载请以链接形式注明出处
本文地址:http://www.juliuschen.com/archives/21.html

 

 

在上述博客中已经描述了KMP算法的基本流程,这里仅对get_next(...)函数中12行进行个说明

为什么12行中要用k = next[k]; 呢,这相当于又是一个模式匹配的问题:

0  1  2  3  4    5  6 

a  b  c  a   b    e  f                当我们求6的next值时,5的next值已经求出为k=2,在5跟2比较时不等,那么下面需要如何在比较呢?

                                           这就有演变成了一个模式匹配的问题

0  1  2  3  4    5  6 

a  b  c  a   b    e  f 

            a   b    c   a   b   e  f  

 

显然下一个要比较的值就是2的next值,即K=next[k]

 

 

 

 

你可能感兴趣的:(KMP算法)