【数据结构--串】朴素模式匹配|KMP模式匹配|KMP模式匹配升级

本博客用来记录自己的学习内容,以便复习。内容取材自《大话数据结构》。

串的匹配算法旨在找到子串T在串S中的位置,可能会有限制条件,即匹配的起始位置:pos

串的基本知识:

串的第一个元素表示串的长度。


朴素模式匹配:

暴力循环解法

//返回子串T在主串S中第pos个字符之后的位置。若不存在,则返回0
int Index(char * S, char * T, int pos)
{
    int i = pos;
    int j = 1;

    while(i <= S[0] && j <= T[0])   
    {
        if(S[i] == T[j])
        {
            i++;
            j++;
        }
        else
        {
            i = i - j + 2;j
            j = 1;
        }
    }

    if(j > T[0])  
    //易错点:这里不能是>=,应为T[0]代表的T串的长度,在循环当中,最后一次j++导致实际值偏大
    {
        return i - T[0];
    }
    else
    {
        return 0;
    }
}

这种匹配方法容易写也容易想,但是时间复杂度最坏可以达到(n-m+1)*m!

于是我们就有了KMP模式匹配。


KMP模式匹配:

在朴素模式匹配当中,我们回溯的是i值,也就是回溯的主串S,但是在KMP模式匹配当中,我们通过回溯j值,即回溯T串来实现对一些特殊情况的优化。

重点!重点!重点!

在需要查找字符串前,先对要查找的字符串做一个分析,这样可以大大减少我们查找的难度,提高查找的速度。

next数组值的推导:

              {0,                 当j=1时

next[j] = {Max{k|1<k<j, 且'p1...pk-1' = 'pj-k+1...pj-1'}                当此集合不为空时

              {1                其他情况

void get_next(char *T, int *next)
{
    int i, k;
    i = 1;
    k = 0;
    next[1] = 0;

    while(i < T[0])
    {
        if(k == 0 || T[i] == T[k])
        {
            ++i;
            ++k;
            //k从0开始,只要相等就加1,所以k(next[i])是前后相等的最大个数。
            next[i] = k;
        }
        else
        {
            k = next[k];  //k值回溯的结果很重要,是next推导的关键
        }
    }
}

匹配算法部分:

//返回子串T在主串S中第pos个字符之后的位置。若不存在,则返回0
int Index_KMP(char * S, char * T, int pos)
{
    int i = pos;
    int j = 1;
    int next[255];
    get_next(T, next);

    while(i <= S[0] && j <= T[0])   
    {
        //注意这里多了j==0的判断
        if(j == 0 || S[i] == T[j])
        {
            i++;
            j++;
        }
        else
        {
            //i = i - j + 2;j
            //j = 1;
            j = next[j];
        }
    }

    if(j > T[0])  
    //易错点:这里不能是>=,应为T[0]代表的T串的长度,在循环当中,最后一次j++导致实际值偏大
    {
        return i - T[0];
    }
    else
    {
        return 0;
    }
}

j = next[j];回溯原理:

当S[i] != T[i]时匹配失败,j指针前移,直到匹配成功,如果一直匹配失败j会归0。

KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下才体现出他的优势,否则两者差异并不明显。


KMP模式匹配升级:

为了解决部分特殊情况,对next数组的推导做出了优化:

void get_nextval(char *T, int *nextval)
{
    int i, k;
    i = 1;
    k = 0;
    nextval[1] = 0;

    while(i < T[0])
    {
        if(k == 0 || T[i] == T[k])
        {
            ++i;
            ++k;
            //next[i] = k;
            if(T[i] != T[k])
            {
                nextval[i] = k;
            }
            else
            {
                nextval[i] = nextval[k];
            }
        }
        else
        {
            k = nextval[k];  //k值回溯的结果很重要,是next推导的关键
        }
    }
}

刚学的时候理解可能比较很困难,只能考记忆,复习多了就能理解了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

活成自己的样子啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值