KMP模式匹配算法中next,nextval的分别实现

next数组定义:

对于这个定义,我的理解是从1~j-1中,前缀与后缀有n个相等,则next[j]=n+1。

例如:t="abcabaa"

当j=1时,next[1]=0。

当j=2时,从1~j-1,串为a,next[2]=1。

当j=3时,从1~j-1,串为ab,next[3]=1。

当j=4时,从1~j-1,串为abc,next[4]=1。

当j=5时,从1~j-1,串为abca,next[5]=2。

当j=6时,从1~j-1,串为abcab,next[6]=3。

当j=7时,从1~j-1,串为abcaba,next[7]=2。

nextval数组,即nextval的改进

他是在计算出next数组的同时,如果第i个字符与他next[i]所指的字符相等,则nextval[i]=nextval[next[i]]。否则,nextval[i]=next[i]。

例如:t="abcabaa"

当j=1时,next[1]=0,nextval[1]=0。

当j=2时,从1~j-1,串为a,next[2]=1,b!=a,nextval[2]=1。

当j=3时,从1~j-1,串为ab,next[3]=1,c!=a,nextval[3]=1。

当j=4时,从1~j-1,串为abc,next[4]=1,a==a,nextval[4]=0。

当j=5时,从1~j-1,串为abca,next[5]=2,b==b,nextval[5]=1。

当j=6时,从1~j-1,串为abcab,next[6]=3,a!=c,nextval[6]=3。

当j=7时,从1~j-1,串为abcaba,next[7]=2,a!=b,nextval[7]=2。

代码:

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
using namespace std;
void get_next(char *t,int *next)
{
    int len=strlen(t+1);
    int i=1,j=0;
    next[i]=j;
    while(i<len)
    {
        if(j==0||t[i]==t[j])//后缀的单个字符与前缀的单个字符
        {
            ++i;
            ++j;
            next[i]=j;
        }
        else
            j=next[j];
    }
//    for(int k=1;k<=len;++k)
//        cout<<next[k]<<" ";
//    cout<<endl;
    return;
}
void get_nextval(char *t,int *nextval)
{
    int i=1,j=0;
    nextval[1]=0;
    int len=strlen(t+1);
    while(i<len)
    {
        if(j==0||t[i]==t[j])
        {
            ++i;
            ++j;
            if(t[i]!=t[j])//若当前字符与前缀字符不相等
                nextval[i]=j;//则当前的j为nextval在i位置的值(即next[i])
            else//若当前字符与前缀字符相等
                nextval[i]=nextval[j];//则将前缀字符的nextval的值赋值给nextval[i],即nextval[i]=next[next[i]];
        }
        else
            j=nextval[j];
    }
//    for(int k=1;k<=len;k++)
//        cout<<nextval[k]<<" ";
//    cout<<endl;
}

//返回子串t在主串s中第pos个字母后的位置
int kmp_next(char *s,char *t,int pos)
{
    int next[105];
    memset(next,0,sizeof(next));
    get_next(t,next);
    int i=pos;
    int j=1;
    int len_s=strlen(s+1);
    int len_t=strlen(t+1);
    while(i<=len_s&&j<=len_t)
    {
        if(j==0||s[i]==t[j])
        {
            ++i;
            ++j;
        }
        else
            j=next[j];
    }
    if(j>len_t)//表示t串匹配成功
        return i-len_t;
    else
        return 0;
}
int kmp_nextval(char *s,char *t,int pos)
{
    int nextval[105];
    memset(nextval,0,sizeof(nextval));
    get_nextval(t,nextval);
    int i=pos;
    int j=1;
    int len_s=strlen(s+1);
    int len_t=strlen(t+1);
    while(i<=len_s&&j<=len_t)
    {
        if(j==0||s[i]==t[j])
        {
            ++i;
            ++j;
        }
        else
            j=nextval[j];
    }
    if(j>len_t)
        return i-len_t;
    else
        return 0;
}
int main()
{
    char t[105],s[105];
    int pos;
    scanf("%s%s%d",s+1,t+1,&pos);
    printf("%d\n",kmp_next(s,t,pos));
    printf("%d\n",kmp_nextval(s,t,pos));
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值