KMP算法

参考《大话数据结构》 P135

 

KMP算法用于字符串匹配,kmp算法完成的任务是:给定两个字符串O和f,长度分别为n和m,判断f是否在O中出现,如果出现则返回出现的位置。常规方法是遍历a的每一个位置,然后从该位置开始和b进行匹配,但是这种方法的复杂度是O(nm)。kmp算法通过一个O(m)的预处理,使匹配的复杂度降为O(n+m)

思想:

朴素匹配算法需要两个指针i,j都遍历一遍字符串,故复杂度m*n

KMP算法i指针不回溯,j指针的回溯参考next数组,体现了动态规划的思想

原理如下:

蓝色表示匹配,红色为失配

分析蓝色部分

如果存在最长公共前后缀的话,比如这样:

就可以在下次匹配的时候用,这样避免了i的回溯

实现:

next数组的意义:当模式匹配串T失效的时候,next数组对应的元素知道应该使用T串的哪个元素进行下一轮匹配

 1 #include <string>
 2 
 3 void get_next(string T, int *next)
 4 {
 5     int i = 1;    //后缀
 6     int j = 0;    //前缀
 7     next[1] = 0;
 8     while (i < T[0])    //T[0]表示字符串长度
 9     {
10         if (j == 0 || T[i] == T[j])
11         {
12             i++;
13             j++;
14             next[i] = j;
15         }
16         else
17             j = next[j];
18     }
19 }
20 
21 int KMP(string S, string T, int pos)
22 {
23     int i = pos;    //标记主串S下标
24     int j = 1;        //匹配串下标
25     int next[255];
26     get_next(T, next);
27     while (i <= S[0] && j <= T[0])    //0位置都放字符串长度
28     {
29         if (j == 0 || S[i] == T[j])
30         {
31             i++;
32             j++;
33         }
34         else
35             j = next[j];    //j退回到合适位置,i不用再回溯了
36         if (j > T[0])    //如果存在j在匹配完最后一个元素后又++了,所以会大于长度
37             return i - T[0];    //i的位置减去匹配串的长度就是匹配串出现的位置
38         else
39             return 0;
40     }
41 }

 

改进

会出现一种特殊情况:

S = “aaaabcde”

T = "aaaaax"

这样的话next数组为012345,实际上由于前面都是a,直接调到第一个a就可以了,期望的next数组为000005

这样next数组构造改为12-15行

 1 void get_next(string T, int *next)
 2 {
 3     int i = 1;    //后缀
 4     int j = 0;    //前缀
 5     next[1] = 0;
 6     while (i < T[0])    //T[0]表示字符串长度
 7     {
 8         if (j == 0 || T[i] == T[j])
 9         {
10             i++;
11             j++;
12             if (T[i] != T[j])
13                 next[i] = j;
14             else
15                 next[i] = next[j];
16         }
17         else
18             j = next[j];
19     }
20 }

 

posted on 2015-11-23 15:37  已停更  阅读(2495)  评论(0编辑  收藏  举报