串的模式匹配算法(BF算法和KMP算法)

子串的定位运算通常称为串的模式匹配串匹配。此运算的应用非常广泛,比如在搜索引擎、拼写检查、语言翻译、数据压缩等应用中,都需要进行串匹配。

设有两个字符串S和T,设S为主串,也称正文串;设T为子串,也称为模式串·。在主串S中找与模式T相匹配的子串,如果匹配成功,确定相匹配的子串中的第一个字符在主串S中出现的位置。

1.BF算法

BF算法,即暴力算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得到最后的匹配结果。

 【算法步骤】

1.分别利用计数指针i和j指示主串S和模式T中当前正待比较的字符串位置,i和j初值为1。

2.如果两个串均未比较到串尾,即i和j均分别小于等于S和T的长度时,则循环执行以下操作:

  • S.ch[i]和T.ch[j]比较,若相等,则j和i分别指示串中的下一个位置,继续比较后面的字符;
  • 若不相等,指针后退重新开始匹配,从主串的下一个字符(i=i-j+2)起再重新与模式的第一个字符(j=1)比较。

3.如果j>T.length,说明模式T中的每一个字符依次和主串S中的一个连续的字符序列相等,则匹配成功。

【算法描述】

int Index_BF(string S, string T)
{
    int i,j;
    i = 1, j= 1;
    while(i<=S.length && j<=T.length)
    {
        if(S.ch[i] == T.ch[j]){i++;j++;}
        else{i=i-j+2;j=1;}
    }
    if(j > T.length)  return i-T.length;  //匹配成功
    else return 0;
}

2.KMP算法

这种改进算法是由克努特(Knuth)、莫里斯(Morris)和普拉特(Pratt)共同设计实现的,因此简称KMP算法。此算法可以在O(n + m)的时间数量级上完成串的模式匹配操作。其改进在于:每当一趟匹配过程中出现字符不等时,无须回溯主串的指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。下面先从具体例子看起。

 如图,在第一趟匹配中,第一个字符a和第二个字符b都匹配,而到第三个字符时,我们发现两个串中的字符不在匹配,所以这时,我们首先要找从不匹配字符的前面的字符是否出现前后缀(前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串;后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串)相等,很明显没有出现前后缀相等,那么i值(i=3)保持该位置,而j回到初值。

在第二趟匹配中,前四个字符a,b,c,a匹配,而到第五个字符时不再匹配,那么就判断前四个字符是否存在前后缀相同,很明显,第一个字符a和第四个字符a相同,那么,i值(i=7)依旧保持该位置,而j则移动到前缀的下一个位置(j=2)。

而到第三次匹配中,模式串的字符和主串字符都相互匹配,那么则匹配成功。

在这三次匹配中,重点是要确定模式串的下一个位置会移动到哪里,那么就引入了另一个知识点:next数组。

next数组在这不会讲的很详细。

1.确定next数组的第一、二位一定分别是0、1,后面求解每一位的next值时,根据前一位进行比较。

2.从第三位开始,将前一位与其next值对应的内容进行比较,如果相等,则该位的next值就是前一位的next值➕1;如果不相等,向前继续寻找next值对应的内容与前一位进行比较,直到找到某位上的内容的next值对应的内容与前一位相等为止,则这个位对应的值➕1,即为需求的next值;

如果找到第一位都没有找到与前一位相等的内容,那么next值为1。

【模式串T的next数组算法】

 

void get_next(string T, int next[])
{
    int i=1,j=0;
    next[1]=0;
    while(i<T.length)
    {
        if(j==0 || T.ch[i] == t.ch[j])
        {
            i++;j++;
            next[i] = j;
        }
        else j=next[j];
    }
}

【KMP算法】

int Index_KMP(string S, string T)
{
    int i=1,j=1;
    int next[T.length+1];
    get_next(T, next);//求模式串的next数组
    while(i<=S.length && j<=T.length)
    {
        if(j==0 || S.ch[i] == T.ch[j])
        {
            i++;j++;
        }
        else j=next[j];
    }
    if(j>T.length) return i-T.length;
    else return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值