字符串匹配之horspool算法(简化的BM算法)

    前面介绍在BF,KMP这些算法的时候老是提到BM这个东西,到底这什么东西,有啥高深的,这些问题我们现在不去考虑。不知道,认真读前几篇文章的读者有没有发现前面的算法都是从模式串的前面开始匹配的,那我们就想能不能从模式串的后面开始匹配了? 答案肯定是可以的。所以这就有了我们今天的这篇文章Horspool算法,这个算法是基于字符串后缀的匹配算法。
在上一篇文章中,我们学习了一个概念叫好字符(又叫好后缀),大家都知道有好必有坏吧,所以我们今天再来学习一个概念-----坏字符。

一、坏字符与模式串滑动

    坏字符是串S中引起匹配失败的字符,坏字符又可以分为两类:
     1. 坏字符不在模式串T中,如下例子

       S: "abbadcababacab", T: "babac", 串S中的字符d就是一个坏字符

    

    对于这种情况,我们直接把模式串向后移动使其T[0]与d的下一位对其,然后从后开始进行下一轮匹配;
    2. 坏字符串在模式串中,如上面例子移动后,从后往前比较,b和c不相同,而字符b在模式串T中出现,此时就把模式串移动到模式串的该字符和串的该坏字符对其,但是如果该坏字符在模式串种出现了不止一次,我们怎么移动了?这时候,为了保守起见,我们移动模式串使模式串种最右端的坏字符和串的该坏字符对其,如下:
    

    如果按照最下面的方法移动,和最左端的字符对其,则可能会漏掉匹配项,如上图所示。

二、知道了坏字符和如何滑动模式串了,计算移动步伐step
    代码的难处在遇到坏字符后该如何移动模式串,即计算移动步伐(step)。
    1. 对于第一种情况,坏字符不在模式串中,直接就T[0]移动到该位置之后,
    

      j=3时发生了不匹配,此时移动步伐(step)=j+1=4.
    2. 对于第二种情况,坏字符在模式串中,为了得到该字符在模式串中的最右位置,需要有一个表记录坏字符在模式串中的最右位置,设其为table[i], 则步伐step= j-table['e'].

三、实现
     //update 2014-06-07
     int horspool(const char *S, const char *T){
          if(S==NULL || T==NULL) return -1;
          int n = strlen(S);
          int m = strlen(T);
          int table[256] = {-1};
          //记录模式串中字符出现的最右位置
          for(int i=0; i<m; ++i)
               table[ T[i] ] = i;
          //移动步伐
          int step = 0;
          for(int i=0; i+m<=n; i+=step){
               step = 0;
               //开始匹配,从右往左匹配
               for( int j=m-1; j>=0; --j){
                    if( S[i+j] != T[j] ){
                         step = j-table[ S[i+j] ];
                         //防止原地踏步
                         if(step <1 )  step = 1;
                         //本轮匹配失败,从新位置开始比较
                         break;
                    }
               }
               //一轮匹配结束后,没有匹配失败的,说明匹配成功
               if(step == 0)  return i;
          }
          return -1;  //匹配失败
     }

四、写在后面的话
字符串匹配这个系列,加上这篇已经写的有4篇文章了,这个系列还剩最后一个算法没有写,有时间了把最后一个算法补上后就这个系列就算是Over了。

如果你觉得本篇对你有收获,请帮顶。
另外,我开通了微信公众号--分享技术之美,我会不定期的分享一些我学习的东西.
你可以搜索公众号: swalge  或者扫描下方二维码关注我

(转载文章请注明出处: http://blog.csdn.net/swagle/article/details/24269403 )


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值