串的匹配算法KMP及改进

KMP模式匹配算法

#include<stdio.h>
#define MAXSIZE 255
typedef unsigned char SString[MAXSIZE+1];//0号单元存放串的长度
void get_next(SString s,int next[])
{

    int i,j;
    next[1]=0;//特殊情况i=1;
     i=1;
     j=0;
     while(i<s[0])
     {
         if(j==0)
         {
             ++i;//先自加1
             ++j;
             next[i]=j;
         }

         else if(s[i]==s[j])
         {


             ++i;
             ++j;
             next[i]=j;
         }
         else
         {

             j=next[j];//不相等j则跳到next[j]的位置
         }
         printf("i=%d,j=%d,next[%d]=%d\n",i,j,i,next[i]);

     }

}
int KMP(SString s,SString t,int pos)
{
    int i=pos;
    int j=1;
    int next[255];
    get_next(t,next);
    while(i<=s[0]&&j<=t[0])
    {
        if(j==0)
        {

            ++i;
            ++j;
        }
        else if(s[i]==t[j])
        {
            printf("i=%d,j=%d,%c=%c\n",i,j,s[i],t[j]);
            ++i;
            ++j;
        }
        else
        {
            j=next[j];
        }
    }
    if(j>t[0])
        return i-t[0];//匹配成功则返回字串的第一个位置
    else
        return 0;
}
int main()
{
    char s[]="abcabab";
    char t[]="caba";
    int i;
    SString str,ttr;
    for( i=0;s[i]!='\0';i++)
        str[i+1]=s[i];
        str[0]=i;

  for( i=0;t[i]!='\0';i++)
    ttr[i+1]=t[i];
    ttr[0]=i;

    printf("位置:%d\n",KMP(str,ttr,1));



    return 0;
}

在这里插入图片描述
KMP算法是为了解决基本的模式匹配的一个缺点,那就是回溯。基本的的模式匹配就是一个两个循环语句,i用来作为主串的下标,j用来作为字串的下标,如果a[i]=b[j],那么i和j都向后移动一个位置,如果a[i]和b[j]不相等,则令i=i-j+1,j=1,这样一来明显的增加了比较的次数,进行了重复遍历。
KMP算法就是为了解决重复遍历的问题,当比较的字符一样时,和基本匹配算法一样,i和j同时往后移动一个位置;不等时,不是像基本匹配算法那样回溯,此时我们的i不变,但是j不是回退到1的位置,而是回退到next[j]的位置。
下面来讨论一下next数组的数值求法:
1.next[1]=0
2.对于j>1,next[j]的求法如下:
取出字符串a[1]—a[j-1],确定这个取出的字符串的前缀和后缀相同部分的字符个数,然后加一,比如aba,个数就为2;aaa
个数就为3
3.不在1和2情况中的a[j]取1
注意:a[2]属于情况3

改进后的KMP

KMP算法虽然有效地解决了回溯重复遍历的问题,但是也存在这样的一个问题,比如主串为aaaabcde,字串为aaaac,next数组为012345,当b与c不等时,会用b与第4个a再比较,结果发现不等。然后再用第3个a与b比较…
其实从第4个a判断之后就没有必要再判断了,因为都是a,既然第4个a不与b匹配,那么前几个a与b必然也不匹配。
所以我们对next数组进行改良,改良后的数组记为nextval
nextval的求法如下:依然要求next,在求出next的同时,进行如下判断,如果在求第j个位置的next时,a[[next[j]]=a[j],那么就令nextval[j]=nextval[next[j]],如果不等,那么nextval[j]还是等于next[j]

#include<stdio.h>
#define MAXSIZE 255
typedef unsigned char SString[MAXSIZE+1];//0号单元存放串的长度
void get_nextval(SString s,int nextval[])
{

    int i,j;
    nextval[1]=0;//特殊情况i=1;
     i=1;
     j=0;
     while(i<s[0])
     {
         if(j==0||s[i]==s[j])
         {
             ++i;//先自加1
             ++j;
             if(s[i]!=s[j])
             nextval[i]=j;
             else
                nextval[i]=nextval[j];
         }
         else
         {

             j=nextval[j];//不相等j则跳到next[j]的位置
         }
         printf("i=%d,j=%d,nextval[%d]=%d\n",i,j,i,nextval[i]);

     }

}
int KMP(SString s,SString t,int pos)
{
    int i=pos;
    int j=1;
    int nextval[255];
    get_nextval(t,nextval);
    while(i<=s[0]&&j<=t[0])
    {
        if(j==0)
        {

            ++i;
            ++j;
        }
        else if(s[i]==t[j])
        {
            printf("i=%d,j=%d,%c=%c\n",i,j,s[i],t[j]);
            ++i;
            ++j;
        }
        else
        {
            j=nextval[j];
        }
    }
    if(j>t[0])
        return i-t[0];//匹配成功则返回字串的第一个位置
    else
        return 0;
}
int main()
{
    char s[]="abcababaaaba";
    char t[]="ababaaaba";
    int i;
    SString str,ttr;
    for( i=0;s[i]!='\0';i++)
        str[i+1]=s[i];
        str[0]=i;

  for( i=0;t[i]!='\0';i++)
    ttr[i+1]=t[i];
    ttr[0]=i;

    printf("位置:%d\n",KMP(str,ttr,1));



    return 0;
}

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CodePanda@GPF

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

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

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

打赏作者

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

抵扣说明:

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

余额充值