KMP算法的实现

KMP算法是两个字符串进行匹配时使用的算法,在原先的暴力匹配法基础上进行了加速,使得时间复杂度降到了O(N)而不再是O(MN),提升了效率。这里只介绍KMP算法的使用方法,不介绍其中的原理和证明过程。

next数组

next数组是是kmp算法得以加速的关键,它表示的是字符串中的某个字符之前的子串,前缀和后缀相同的最大长度。这里注意对于字符串中的每一个字符,next数组都要有对应的值。
求出next数组的方法,如果前后缀相同,则next数组对应位置的值在前一位的基础上加1,如果不同,则需要回退。

vector<int> get_next(string str2)
{
    int n2=str2.length();
    if(n2==1)
    {
        return {-1};
    }
    vector<int> next(n2,0);
    next[0]=-1;next[1]=0;//人为规定
    int i=2,k=0;//i用于遍历,k用于比对
    while(i<n2)
    {
        if(str2[i-1]==str2[k])//前后缀相同
        {
            ++k;
            next[i]=k;
            ++i;
        }else if(k>0)//前后缀不同,且k值可回退
        {
            k=next[k-1];
        }else//前后缀不同,且k值为0,不可回退
        {
            ++i;//next数组已都初始化为0,这里不用修改
        }
    }
    return next;
}

匹配过程

这里先说一下暴力法,暴力法与KMP算法有一点相似,都是会将两个字符串中的字符一一比对。不同之处在于,对于暴力法,如果匹配失败,原字符串对应的指针回退到一开始匹配的后一位,而子串则需要从头重新匹配。而KMP算法的加速之处在于原字符串指针不动,子串指针也不需要立即回退到开头。这一过程也可以换个角度理解,暴力法是在匹配失败后,将子串一个字符一个字符地往后推,而KMP算法可以一次性将子串向后推多个字符。

int kmp(string str1,string str2)
{
    int n1=str1.length();//str1是原字符串
    int n2=str2.length();//str2是需进行匹配的子串
    if(n1<n2)
    {
        return -1;
    }
    vector<int> next=get_next(str2);
    int i1=0,i2=0;//遍历两个字符串的指针
    while(i1<n1&&i2<n2)
    {
        if(str1[i1]==str2[i2])//两字符串对应字符匹配成功
        {
            ++i1;
            ++i2;
        }else if(i2>0)//匹配失败,i2回退
        {
            i2=next[i2];
        }else//匹配失败,且i2不可回退
        {
            ++i1;
        }
    }
    return i2==n2?i1-i2:-1;//i2==n2即为匹配成功,返回str1对应首字符的下标
}

对数器

这里还是再贴出对数器的代码,随机生成字符串进行对比(这里的随机生成方法较为粗糙,可以改进)。可以将暴力法和KMP算法生成的结果进行对比。

int compare()
{
    int len1=rand()&63;
    int len2=rand()&31;
    for(int times=1;times<=TIME_N;++times)
    {
        string str1(len1,0),str2(len2,0);
        for(int i=0;i<len1;++i)
        {
            str1[i]=1+rand()%126;
        }
        for(int i=0;i<len2;++i)
        {
            str2[i]=1+rand()%126;
        }
        int ret1=kmp1(str1,str2);
        int ret2=kmp2(str1,str2);
        if(ret1!=ret2)
        {
            return times;
        }
    }
    return 0;
}

这里字符串匹配函数的返回值,匹配失败返回-1,成功返回匹配成功时子串的第一个字符在原字符串中对应位置的下标。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值