C语言KMP字符串匹配算法


KMP算法模版

Kmp算法是用于求一长字符串和短字符串按一定规律匹配的情况,可以求是否能在长串中找到短串

         其思想就是通过一个next数组对短串进行处理,找到短串前后某两个位置是否具有相同的前后缀,用next[i]表示最后以b[i]结尾的前缀和后缀与模式串前缀的最长匹配数。

这样两字符串在匹配是,若在长串与短串某位置发现两字符不同,不能继续匹配时,短串下标i不一定要回到短串的首字符继续匹配,短串可以跳到next[i]的位置。从而降低算法的时间复杂度,从原来的O(n*m)降低到O(n+m)。//n,m表示两串长度

代码如下:

#include<cstdio>
#include<cstring>
const int Max=10010;
char str[Max],str1[Max];//这里匹配的的浪字符串,Kmp算法也可用于两个数组等。
int nextt[Max];
void Next(int len)
{
    int i=-1,j=0;//将i初始化为-1,是为了维护两个指针i,j,便于对next数组进行初始化,保证i在j前
    nextt[0]=-1; //将短串首字符的next值赋值为-1,便于后面Kmp()函数循环中i跳到到短串首时做特殊处理
    while(j<len)
    {
        if(i==-1||str[i]==str[j])//i==-1时,也需要将i,j进行自增,才能保证i在j之前,此时i==0,j==1.并把next[1]=0,
        {                        //即短串第二个字符b[1]的前缀下标为0.在j循环过程中,i做相应的变化。若发现j位置与i位置
            ++i,++j;             //存在相同的前缀,则用nextt[j]=i记录下来,用于Kmp()函数中匹配时运用
            nextt[j]=i;
        }
        else
            i=nextt[i];      //若短串中i位置和j位置字符不同,i跳到next[i]位置  原因:当短串中i位置和j位置字符不等时,说明
    }                        //此时i位置和j位置没有相同的前缀,但可能在i位置以前找到与j+1位置相同的前缀
    for(int i=0; i<=len; i++)                 //输出next数组的值
        printf("%d%c",nextt[i],i==len?'\n':' ');
    return ;
}
int Kmp(int len,int len1)
{
    int i=0,j=0;
    while(j<len1)//以长串长度做循环的终止条件
    {
        if(i==-1||str[i]==str1[j])
        {
            ++i,++j;
        }
        else
            i=nextt[i];
        if(i==len)  //当i==len时,说明短串已到达结尾b[len-1],在if中自增以后其值与len相同
            return 1;  //此时表明在长串中找到了符合条件的短串,程序返回1.若程序到循环终止在长串中也没有
    }                  //找到符合条件的短串,返回0
    return 0;
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%s %s",str,str1);//str为短串,str1为长串
        int len=strlen(str);
        int len1=strlen(str1);
        Next(len);
        if(Kmp(len,len1))//len为短串长度,len1为长串长度,以这两个长度做Kmp()函数循环的终止条件
            printf("Yes\n");  //函数也可能在没到终止条件是结束,此时匹配已经完成!即在Kmp()函数
        else                  //结束条件之前在长串中已经找到了符合条件的短串
            printf("No\n");
        if(nextt[len]&&len%(len-nextt[len])==0)//求循环节(最长前后缀循环次数),len为短串长度,next[len]表示最后b[len-1]结尾的前缀和后缀
        {                                      //与模式串前缀的最长匹配数。则len-next[len]为循环节长度,len/(len-nextt[len])即为循环节
            printf("%d\n",len/(len-nextt[len]));
        }
        else
            printf("Can't\n");
    }
    return 0;
}
希望对大家有所帮助。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值