改进的KMP算法

KMP算法是字符串间进行匹配的一种算法,区别于一般的简单模式匹配算法。

假设有主串s和子串t,判断t是否是s的子串???

一般的算法是将s[i]和t[j]逐个比较,当s[i]==t[j]时i++;j++;当s[i]!=t[j]时,i和j的值回溯i=i-j+1;j=0;这种算法当遇到子串t有较多元素重复或者s和t有较多相同时是比较低效的,

所以采用KMP算法。

KMP算法的核心是采用一个数组next存储子串t每次回溯的位置,且i的值不用回溯。

下面我们看一个例子:

主串:a b c a b c a b c.....

下标:1 2 3 4 5 6 7 8 9

子串:a b c a b x

下标:1 2 3 4 5 6

很明显主串和子串前5个字符是相等的,但第六个c和x不相等,采用KMP的话就可以i的值为6,然后j的值为3,也就是这样

                         i

主串:a b c a b c a b c.....

下标:1 2 3 4 5 6 7 8 9

                         j

子串:        a b c a b x

下标:        1 2 3 4 5 6

至于j为什么是3,其实是由子串s自己决定的。

子串abcabx的next数组:

next: 0  1  1  1  2  3

首先next[1]=0,然后next[2]看前面有多少个前后缀是相同的,很明显next[2]是0个所以是1,next[3]是ab也是0个所以是1,next[4]是abc也是1,next[5]是abca,a和最后一个a相同,所以next[5]=2,next[6]是abcab有前面两个ab和后面两个ab相同,所以next[6]=3.

求next数组的函数:

void get_next(char *t,int *next,int t_lenth)

{

       int i,j;

       i=1;j=0;

       next[1]=0;

       while(i<t_lenth)

      {

          //t[i]表示后缀字符,t[j]表示前缀字符

          if(j==0||t[i]==t[j])

          {

                i++;

                j++;

                next[i]=j;

           }

          else 

                j=next[j];//回溯

       }

}

主函数:

int main(void)
{
    char S_str[MAXSIZE],T_str[MAXSIZE];
    int nextval[MAXSIZE];
    int s_lenth,t_lenth;
    int N,i,j,k;
    scanf("%d",&N);
    for(k=0;k<N;k++)
    {
        scanf("%s",S_str+1);
        scanf("%s",T_str+1);
 
        s_lenth=0;j=1;//主串长度
        while(S_str[j++]!='\0') s_lenth++;
 
        t_lenth=0;j=1;//子串长度
        while(T_str[j++]!='\0') t_lenth++;
 
        //计算nextval数组
        get_nextval(T_str,nextval,t_lenth);
 
        //查看是否匹配
        i=j=1;
        while(i<=s_lenth&&j<=t_lenth)
        {
            if(j==0||S_str[i]==T_str[j])
            {
                i++;
                j++;
            }
 
            else
                j=nextval[j];
        }
 
        if(j>t_lenth)
            printf("yes\n");
        else printf("no\n");
    }
 
    return 0;
}
 改进的KMP算法: 

其实是为了预防子串是:xxxxxxxb这种前面有多个重复的情况

假设主串:aaaaaaccc....

       子串:aaaaaab

运用原来的KMP,i的值会到7,根据next数组,j的值会从7到1,前面6个a是都是相同的,第6个a和c不同,为什么还要比较下去呢?所以我们对next数组进行了优化成nextval数组。

求nextval数组的函数:

//计算nextval数组函数
void get_nextval(char *t,int *nextval,int t_lenth)
{
    int i,j;
    i=1;j=0;
    nextval[1]=0;
    while(i<t_lenth)
    {
        if(j==0||t[i]==t[j])//t[i]表示后缀字符,t[j]表示前缀字符
        {
            i++;
            j++;
            if(t[i]!=t[j])//当前字符与前缀字符不同
                nextval[i]=j;
            else
                nextval[i]=nextval[j];
        }
        else
            j=nextval[j];//j回溯
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值