kmp算法研究

来源:互联网 发布:手机淘宝买东西步骤 编辑:程序博客网 时间:2024/06/02 02:32

    这段时间在看关于kmp算法的内容,其中尤其是matrix67大牛的那篇kmp算法详解,网上评价很高。说实话一开始看没怎么看懂,后面主要结合代码仔细跟了跟, 思路清晰了很多。kmp算法的关键在于利用字符串自身的特点在一处不能匹配后大幅移动,从而将效率降为线性的。

    此文并不是从头讲kmp的原理等东西,只是说说自己的一些想法。如果对于kmp想要从头了解的话,可以参考matrix67大牛和网上其他大牛的著作。

    kmp的关键在于,预处理 存放当不能匹配时下一个匹配位置的数组。也就是自我匹配的过程,其中P[j]应该是所有满足B[1..P[j]]=B[j-P[j]+1..j]的最大值。

    matrix67大牛的代码是

P[1]:=0;j:=0;for i:=2 to m dobegin   while (j>0) and (B[j+1]<>B[i]) do j:=P[j];   if B[j+1]=B[i] then j:=j+1;   P[i]:=j;end;
这是Pascal的代码,将其改成C的便是

dst[0] = -1;j = -1;for (i = 1; i < strlen(src); i++){    while ((j > -1) && (src[j + 1] != src[i]))    {        j = dst[j];    }    if (src[j+ 1] == src[i])    {        j++;    }    dst[i] = j;}

中间稍作了些处理

如果输入为:

char src[] = "abababacaba";

运行结果为:

src[]:  a  b  a  b  a  b  a  c  a  b  a dst[]: -1 -1  0  1  2  3  4 -1  0  1  2 


但是中间的-1,0会让人很晕。其实都是需要从头匹配的意思,均可以改成零,这样可以更好得理解。

自己写了个函数可以更方便的用

void kmp_get_next(const char *src, int *dst){    int i, j, len_src;    dst[0] = 0;    j = 0;    len_src = strlen(src);    for (i = 1; i < len_src; i++)    {        while ((j > 0) && (src[j] != src[i]))        {            j = dst[j];        }        dst[i] = j;        if (src[j] == src[i])        {            j++;        }            }    return ;}
运行结果为
src[]: a  b  a  b  a  b  a  c  a  b  a dst[]: 0  0  0  1  2  3  4  0  0  1  2 


当然,最终的kmp匹配的函数也需要相应修改


int kmp_matching(const char *dst,       //待检查的字符串                 const char *match_str, //匹配字符串                 int *match_arr         //预处理数组                ){    int count = 0;                      //计数,匹配成功次数    int i, j = 0;    int len_dst = strlen(dst);    int len_match = strlen(match_str);    for (i = 0; i < len_dst; i++)    {        while ((j > 0) && (dst[i] != match_str[j]))        {            j = match_arr[j];        }        if (dst[i] == match_str[j])        {            j++;        }        if (j == len_match)        {            printf("one matching at %d\n", i - len_match + 1);            j = match_arr[j];            count++;        }    }    if (count == 0)    {        printf("no matching\n");    }    return count;}

此外,生成的预处理数组空间还可以用malloc的方式动态开辟。将这两个函数一封装,就可以成为一个模块了。

总的来说,整体的思想没变,只是对其中稍作修改,便于自己深入理解而已


转贴请注明出处