kmp算法研究

    这段时间在看关于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 do
begin
   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的方式动态开辟。将这两个函数一封装,就可以成为一个模块了。

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


转贴请注明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值