您的位置:首页 > 其它

浅谈KMP算法

2017-10-21 14:01 169 查看
    课上学了KMP算法之后有几个地方很是迷茫,课下就查了点资料,这里做下总结,今后忘了还能回来看一下。

    首先,KMP算法的主要目的就是比较两个字符串时避免不必要的回溯。一个字符串可能会出现字符串头部和尾部有重复的现象,KMP算法就是根据这个现象,在比较字串时,不在简单地向后移一位,而是在后移时,跳过首位相同的部分再开始比较。例如:判断 ABCDABD 是否是 ABCDABEABCDABD 的子串,

   ABCDABEABCDABD

   ABCDABD

判断到第6位时 E 和 D 不同,但它的前两位 AB 和 子串的前两位 AB 相同,所以之后直接移动到

   ABCDABEABCDABD

              ABCDABD

所以这时子串和 E 比较的位的 C 的下标就等于 D 的前一位 B 的首位重复的位数

这里就需要对子串进行一个预处理,就是算出它的每一位对应的部分匹配值,也就是前后重复的位数,对于 ABCDABD 来说,就是 0000120,先上代码

#include <string>
#include <assert.h>

int* Next(string P){
int m = P.length();
assert( m > 0 ); //若 m = 0 则退出
int *N = new int[m];
assert( N != NULL );
N[0] = 0;
for(int i = 1; i < m; i ++){
int k = N[i - 1];
while(k > 0 && P[i] != P[k]){
k = N[k - 1];
}
if(P[i] == P[k]){
N[i] = k + 1;
}else{
N[i] = 0;
}
}
return N;
}其中 k 表示尾部要进行比较的上一位有几个字符重复,也代表接下来头部要进行比较的位的下标,k - 1 表示比较时头部重复部分最后一个字符的下标,i 表示第 i 个字符

我比较难理解的就主要是
while(k > 0 && P[i] != P[k]){
k = N[k - 1];
}
这两行,翻译成中文就是 当一个子串满足去掉一个字符重复 k 个,加上这个字符却不重复 k + 1 个时,对于这个字符来说,它的重复个数等于当前头部重复部分最后一个字符的重复个数,满足条件则继续循环
循环出来后,条件应该为k == 0 || P[i] == P[k],之后的逻辑就简单了,如果前等于后,重复个数就加1,否则为0

KMP算法的代码就是

int KMPStrMartching(string T, string P, int startIndex){ //判断P是否为T的子串,是的话返回开始的下标
int *N = Next(P);
int lastIndex = T.length() - P.length();
if((lastIndex - startIndex) < 0)
return (-1);
int i = 0, j = 0;
for(i = startIndex; i < T.length(); i ++){
while(P[j] != T[i] && j > 0)
j = N[j - 1];
if(P[j] == T[i])
j ++;
if(j == P.length()){
delete N;
N = NULL;
return (i - j + 1);
}
}
delete N;
N = NULL;
return (-1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 kmp