Karp Rabin 算法

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

KR算法對模式串和循環中每一次要匹配的子串按必定的hash函數求值,若是hash值相同,才進一步比較這兩個串是否真正相等app

 

本文使用的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的素數。spa

計算時,*2的運算就使用移位代替了.net

 

在下面的實現代碼中,q取整形最大值,也就是說,能夠不用進行模運算了,這種偷工減料的作法只能在模式串很短的情形下才能夠用,要否則會溢出的。粗略算了一下,若是模式串是ascii 英文字符,那麼模式串長度不超過25的狀況下,在32 位機上是沒問題的orm

 

舉例說一下KR算法吧:blog

在我寫的這個總結中,各個算法使用的例子都同樣,隨便找的;ci

模式串 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的錯誤率,而很實用

相關文章
相關標籤/搜索