Karp Rabin 算法

Karp Rabin 算法是利用hash函数的特性进行字符串匹配的。

KR算法对模式串和循环中每一次要匹配的子串按一定的hash函数求值,如果hash值相同,才进一步比较这两个串是否真正相等

 

本文使用的hash函数如下:

hash(str[0..m-1])=(str[0]*2^(m-1)+str[1]*2^(m-2)+……+str[m-1]*2^0)mod q

q是一个较大的数,而且最好是素数,而且是大于m的素数。

计算时,*2的运算就使用移位代替了

 

在下面的实现代码中,q取整形最大值,也就是说,可以不用进行模运算了,这种偷工减料的做法只能在模式串很短的情形下才可以用,要不然会溢出的。粗略算了一下,如果模式串是ascii 英文字符,那么模式串长度不超过25的情况下,在32 位机上是没问题的

 

举例说一下KR算法吧:

在我写的这个总结中,各个算法使用的例子都一样,随便找的;

模式串 pattern="pappar"

文本串 text="pappappapparrassanuaragh";

pattern 长度记 pattern_len

预备阶段就是计算pattern的hash,长度为6,那么hash_pattern='p'*2^5+'a'*2^4+'p'*2^3+'p'*2^2+'a'*2^1+'r'*2^0

当然,这里使用的是字符的ascii值

也计算text前六个字符的hash,我们记第一个为hash_text[0]

然后就开始向前移动了,在移动时,要重新计算当前与模式串对应的串的hash值,这个工作叫rehash

初始化 i=0

如果 hash_pattern与hash_text[i]相等,返回 i

如果不等 计算新的hash值,就是text[i..i+patten_len]的hash,

当然这里不会像第一次那样全部计算,方法是

上一次计算的值减去上一次匹配时串的第一个字符乘以 2^pattern_len ,然后乘以2,再加上新加入比较的字符值

根据公式可以很清晰看出来。

就是减去计算中的第一项,把剩下的乘以2,然后在末尾加入新增的字符值

 

看代码吧,很简答的

[cpp] view plaincopy

  1. //Karp-Rabin algorithm,a simple edition  

  2. int karp_rabin_search(const char* text,const int text_len,const char* pattern,const int pattern_len)  

  3. {  

  4.     int hash_text=0;  

  5.     int hash_pattern=0;  

  6.     int i;  

  7.       

  8.     //rehash constant:2^(pattern_len-1)  

  9.     int hash_const=1;  

  10.     /*for (i=1;i<pattern_len;i++){ 

  11.         hash_const<<=1; 

  12.     }*/  

  13.     hash_const<<=pattern_len-1;  

  14.   

  15.     //preprocessing  

  16.     //hashing  

  17.     for (i=0;i<pattern_len;++i){  

  18.         hash_pattern=(hash_pattern<<1)+pattern[i];  

  19.         hash_text=(hash_text<<1)+text[i];  

  20.     }  

  21.   

  22.     //searching  

  23.     for (i=0;i<=text_len-pattern_len;++i){  

  24.         if (hash_pattern==hash_text&&memcmp(text+i,pattern,pattern_len)==0){  

  25.             return i;  

  26.         }else{  

  27.             //rehash  

  28.             hash_text=((hash_text-text[i]*hash_const)<<1)+text[i+pattern_len];  

  29.         }  

  30.     }  

  31.     return -1;  

  32. }  

hash函数的好坏会直接影响算法的效率,一般应遵循这样的规则:

1  要容易计算,本文中用的就不错,移位的速度大家是知道的

    而且在rehash,就是重新计算hash值时,hash的构造要能避免重新计算整个串的hash,而应该像本例中用到的那样,可以动态地很容易地更新

2 字符串hash值要尽量分布均匀,减少冲突,这是hash函数在任何场合的要求。做到这一点,就能减少匹配中字符的一个个比较,提高性能。如果能够保证每个串的hash值不同,就不用再比较字符了,可以省掉代码中的memcmp运算

   Monte Carlo改进的 RK算法就是只比较hash值,虽然那个改进的算法不能保证正确的结果,但以低于2.53/pattern_len的错误率,而很实用

转载于:https://my.oschina.net/u/1462613/blog/226239

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值