朴素的模式匹配算法和快速模式匹配算法(KMP)

朴素的模式匹配算法和快速模式匹配算法(KMP)
字符串的模式匹配

  • 寻找字符串p在字符串t中首次出现的起始位置称为字符串的模式匹配,其中称p为模式(Pattern),t为正文(Text)
    1、朴素的模式匹配算法
  • 基本思想:用p中的每个字符去与t中的字符一一比较。比较成功返回1;比较失败,正文t的下标向后移动一位,直到比较成功。如若t的剩余字符的长度小于p的长度还未匹配成功,则返回-1。
    在这里插入图片描述
  • n代表正文t的长度,m代表模式字符串p的长度。
int index(seqstring p,seqstring t) {
    int i = 0;//扫描正文t
    int j;//扫描模式p
    int success = 0;//匹配成功的标志
    while((i<=p.length - t.length) && (!success)) {//如果整体匹配不成功,且t剩余字符长度够长。
        j = 0;
        success = 1;
        while((j < p.length) && success) {//局部匹配成功
            if(p.str[j] != t.str[i + j]) 
                success = 0;
            else 
                j ++;
        }
        i ++;
    }
    if(success) 
        return (i - 1);
    else
        return -1;
}
  • 时间复杂度O((n-m+1)*m)

2、快速模式匹配算法(KMP算法)
在这里插入图片描述

  • 4-1表示此次匹配从p0与tk开始比较,当比较到pi与tr时出现不等情况。
  • 4-2表示【p0pi-2】=【p1pi-1】。模式p中pi之前存在长度为i-1的真前缀和真后缀的匹配。
  • 4-3表示【p0pi-3】=【p2pi-1】。模式p中pi之前存在长度为i-2的真前缀和真后缀的匹配。
  • 考虑一般情况:如模式p中pi之前最长真前缀和真后缀匹配的长度为j,当pi !=tr时,则下一步只需从pj与tr开始继续后继对应字符比较。
  • 根据上述分析,在模式匹配的过程中,每当出现pi != tr时,下一次与tr进行比较的pj和模式p中pi之前最长真前缀和真后缀匹配的长度密切相关。
  • 于是,可以针对模式p定义一个数组next[m],其中next[i]表示当pi != tr时,pi之前最长真前缀和最长真后缀的长度j,那么,获取到这个值后,下一次比较就可以从pj开始和tr比较,即pnext[i]和tr比较。
//求next数组
void getnext(seqstring p,int next[]) {
    int i = 0;
    int j = -1;
    next[0] = -1;
    while(i < p.length-1) {
        if(j==-1 || p.str[i] == p.str[j]) {
            next[++ i] = ++ j;
        } else {
            j = next[j];
        }
    }
}
  • next[0] = -1 表明当p0 != tr时将从p-1与tr开始继续后记对应字符的比较;然而p-1是不存在的,我们可以将这种情况理解成下一步将从p0与tr+1开始后记对应字符比较。
  • next[i]时已得到pi之前的最长真前缀和真后缀的长度j。
  • 如果此时进一步有pj=pi,则pi+1之前的最长真前缀与真后缀的匹配长度为j+1,即next[i+1]=j+1。
  • 如果此时进一步有pj != pi,这里本质上还是一个模式匹配问题(p和p模式匹配),因此应该检查pnext[j]和pi是否相等,如果相等,则next[i+1]=next[j] + 1。如果不相等,则再取pnext[next[j]]与pi进行比较,直至要将p-1与pi比较为止,此时next[i+1]=0.
//字符串KMP模式匹配算法实现
int kmp(seqstring t,seqstring p,int next[]) {
    int i = 0;
    int j = 0;
    while(i<t.length && j < p.length) {
        if(j == -1 || t.str[i] == p.str[j]) {
            i++;
            j++;
        } else {
            j = next[j];
        }
    }
    if(j == p.length) //模式匹配成功
        return i-p.length;
    else //模式匹配失败
        return -1;
}
  • 时间复杂度O(m+n)
    3、KMP模式匹配小结
  • 这里的重点就在于最长真前缀和真后缀的是否相同。
  • 当某处出现不匹配的时候,我们就可以通过最长真前缀和最长真后缀的匹配长度j来移动p并且从pj开始继续比对,而就不仅仅是像朴素模式匹配算法那样移动一位且从头开始比对。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值