浅谈KMP算法

来源:互联网 发布:域名ip地址查询 编辑:程序博客网 时间:2024/06/03 19:24

    课上学了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);}