KMP字符串模式匹配算法之失败回退(部分摘抄)

今天看KMP算法,对于next函数的理解一直有些困难,找了好久网上的资料,老师的PPT,最后终于找到了一个我可以理解的说法。

有关KMP算法,因为模式匹配(找字符串子串位置)使用暴力回溯很浪费时间,所以诞生了KMP算法。KMP算法引用了一个next函数,计算目标字符串的next参数,这里有两种标记方法,我比较倾向于以-1开头的,因为可以把它看做位移,便于我的理解;另一种是0开头的。

KMP:

(1)next算法:使用递推的方法,next[1]=0;next[j]=k;next[j+1]=?

        这里有两种情况,一种是p[j] = p[k] (这里的j和k都是下一循环中的),这个就直接让next[j+1]=k+1就可以了。

        另外一种情况,是我弄了好久才搞懂的地方,就是这一句“k=next[k]”,课本上就这么一句话,简直horrible!不过,幸运的是我在网上找了一个和我有同样烦恼的前辈,然后把他的文章附在这里:KMP

他里面讲的主要是,如果匹配失败了,需要回退,回退到这个前面n个位置,这里的n是返回失配位之前最长公共前后缀对应的前缀后一位的地方。这句话,是这个大佬说的,我觉得比较容易理解理解。

(2)KMP算法

类似我之前说的,把next看做位移,就很好理解了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
void cal_next(char *str, int *next, int len)
{
    next[0] = -1;
    int k = -1;
    for (int q = 1; q <= len-1; q++)
    {
        while (k > -1 && str[k + 1] != str[q])
        {
            k = next[k];
        }
        if (str[k + 1] == str[q])
        {
            k = k + 1;
        }
        next[q] = k;
    }
}
int KMP(char *str, int slen, char *ptr, int plen)
{
    int *next = new int[plen];
    cal_next(ptr, next, plen);
    int k = -1;
    for (int i = 0; i < slen; i++)
    {
        while (k >-1&& ptr[k + 1] != str[i])
            k = next[k];
        if (ptr[k + 1] == str[i])
            k = k + 1;
        if (k == plen-1)
        {
            //cout << "在位置" << i-plen+1<< endl;
            //k = -1;//重新初始化,寻找下一个
            //i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠)
            return i-plen+1;
        }
    }
    return -1;
}
int main()
{
    char *str = "bacbababadababacambabacaddababacasdsd";
    char *ptr = "ababaca";
    int a = KMP(str, 36, ptr, 7);
    printf("%d",a);
    return 0;
}

代码摘抄来自:link

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小小姝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值