常見hash算法

hash算法的意義在於提供了一種快速存取數據的方法,它用一種算法創建鍵值與真實值之間的對應關係,(每個真實值只能有一個鍵值,可是一個鍵值能夠對應多個真實值),這樣能夠快速在數組等條件中裏面存取數據.  算法

   在網上看了很多HASH資料,因此對HASH的相關資料進行總結和收集。  
  //HashTable.h template class HashTable{ public : HashTable( int count ) ; void put( T* t ,int key ) ; T* get( int key ) ; private : T** tArray ; }  
  //HashTable.cpp template HashTable::HashTable( int count ){ tArray = new T*[count] ;} template void HashTable::put( T* t , int key ){ this->tArray[ key ] = t ;}template T* HashTable::get( int key ) { return this->tArray[ key ] ;}  
  這樣,咱們只要知道key值,就能夠快速存取T類型的數據,而不用像在鏈表等數據結構中查找同樣, 要找來找去的. 至於key值,通常都是用某種算法(所謂的Hash算法)算出來的.例如:字符串的Hash算法, char* value = "hello"; int key = (((((((27* (int)'h'+27)* (int)'e') + 27) * (int)'l') + 27) * (int)'l' +27) * 27 ) + (int)'o' ; Hash函數處理流程Hash,通常翻譯作"散列",也有直接音譯爲"哈希"的,就是把任意長度的輸入(又叫作預映射, pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。簡單的說就是一種將任意內容的輸入轉換成相同長度輸出的加密方式. 
    
我來作一個比喻吧。  
咱們有不少的小豬,每一個的體重都不同,假設體重分佈比較平均(咱們考慮到公斤級別),咱們按照體重來分,劃分紅100個小豬圈。  
而後把每一個小豬,按照體重趕進各自的豬圈裏,記錄檔案。 
好了,若是咱們要找某個小豬怎麼辦呢?咱們須要每一個豬圈,每一個小豬的比對嗎?  
固然不須要了。 
咱們先看看要找的這個小豬的體重,而後就找到了對應的豬圈了。  
在這個豬圈裏的小豬的數量就相對不多了。  
咱們在這個豬圈裏就能夠相對快的找到咱們要找到的那個小豬了。 
對應於hash算法。  
就是按照hashcode分配不一樣的豬圈,將hashcode相同的豬放到一個豬圈裏。  
查找的時候,先找到hashcode對應的豬圈,而後在逐個比較裏面的小豬。 
因此問題的關鍵就是建造多少個豬圈比較合適。 
若是每一個小豬的體重所有不一樣(考慮到毫克級別),每一個都建一個豬圈,那麼咱們能夠最快速度的找到這頭豬。缺點就是,建造那麼多豬圈的費用有點過高了。 
若是咱們按照10公斤級別進行劃分,那麼建造的豬圈只有幾個吧,那麼每一個圈裏的小豬就不少了。咱們雖然能夠很快的找到豬圈,但從這個豬圈裏逐個肯定那頭小豬也是很累的。 
因此,好的hashcode,能夠根據實際狀況,根據具體的需求,在時間成本(更多的豬圈,更快的速度)和空間本(更少的豬圈,更低的空間需求)之間平衡。 
  
Hash算法有不少不少種類。具體的能夠參考以前我寫的Hash算法的一些分析。本處給你們提供一個集合了不少使用的Hash算法的類,應該能夠知足很多人的須要的: 
Java代碼  
  
經常使用的字符串Hash函數還有ELFHash,APHash等等,都是十分簡單有效的方法。這些函數使用位運算使得每個字符都對最後的函數值產生影響。另外還有以MD5和SHA1爲表明的雜湊函數,這些函數幾乎不可能找到碰撞。 
經常使用字符串哈希函數有BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。對於以上幾種哈希函數,我對其進行了一個小小的評測。 

Hash函數                數據1 數據2 數據3      數據4                     數據1得分    數據2得分       數據3得分        數據4得分        平均分 
BKDRHash              2        0        4774      481                         96.55            100                   90.95               82.05                92.64 
APHash                   2        3        4754      493                          96.55            88.46               100                  51.28                86.28 
DJBHash                 2        2        4975      474                          96.55            92.31                0                    100                    83.43 
JSHash                   1         4        4761     506                          100               84.62               96.83               17.95                 81.94 
RSHash                  1         0        4861     505                          100                100                 51.58               20.51                 75.96 
SDBMHash             3        2         4849     504                          93.1              92.31               57.01               23.08                72.41 
PJWHash               30      26        4878     513                          0                   0                     43.89                0                       21.95 
ELFHash                30      26        4878     513                          0                   0                     43.89                0                        21.95 
  


其中數據1爲100000個字母和數字組成的隨機串哈希衝突個數。數據2爲100000個有意義的英文句子哈希衝突個數。數據3爲數據1的哈希值與1000003(大素數)求模後存儲到線性表中衝突的個數。數據4爲數據1的哈希值與10000019(更大素數)求模後存儲到線性表中衝突的個數。 


通過比較,得出以上平均得分。平均數爲平方平均數。能夠發現,BKDRHash不管是在實際效果仍是編碼實現中,效果都是最突出的。APHash也是較爲優秀的算法。DJBHash,JSHash,RSHash與SDBMHash各有千秋。PJWHash與ELFHash效果最差,但得分類似,其算法本質是類似的。 

數組

#define M  249997
#define M1 1000001
#define M2 0xF0000000
   
// RS Hash Function 
unsigned int RSHash(char*str) { unsigned int b=378551 ; unsigned int a=63689 ; unsigned int hash=0 ; while(*str) { hash=hash*a+(*str++); a*=b ; } return(hash % M); } // JS Hash Function 
unsigned int JSHash(char*str) { unsigned int hash=1315423911 ; while(*str) { hash^=((hash<<5)+(*str++)+(hash>>2)); } return(hash % M); } // P. J. Weinberger Hash Function 
unsigned int PJWHash(char*str) { unsigned int BitsInUnignedInt=(unsigned int)(sizeof(unsigned int)*8); unsigned int ThreeQuarters=(unsigned int)((BitsInUnignedInt*3)/4); unsigned int OneEighth=(unsigned int)(BitsInUnignedInt/8); unsigned int HighBits=(unsigned int)(0xFFFFFFFF)<<(BitsInUnignedInt-OneEighth); unsigned int hash=0 ; unsigned int test=0 ; while(*str) { hash=(hash<<OneEighth)+(*str++); if((test=hash&HighBits)!=0) { hash=((hash^(test>>ThreeQuarters))&(~HighBits)); } } return(hash % M); } // ELF Hash Function 
unsigned int ELFHash(char*str) { unsigned int hash=0 ; unsigned int x=0 ; while(*str) { hash=(hash<<4)+(*str++); if((x=hash&0xF0000000L)!=0) { hash^=(x>>24); hash&=~x ; } } return(hash % M); } // BKDR Hash Function 
unsigned int BKDRHash(char*str) { unsigned int seed=131 ;// 31 131 1313 13131 131313 etc.. 
    unsigned int hash=0 ; while(*str) { hash=hash*seed+(*str++); } return(hash % M); } // SDBM Hash Function 
unsigned int SDBMHash(char*str) { unsigned int hash=0 ; while(*str) { hash=(*str++)+(hash<<6)+(hash<<16)-hash ; } return(hash % M); } // DJB Hash Function 
unsigned int DJBHash(char*str) { unsigned int hash=5381 ; while(*str) { hash+=(hash<<5)+(*str++); } return(hash % M); } // AP Hash Function 
unsigned int APHash(char*str) { unsigned int hash=0 ; int i ; for(i=0;*str;i++) { if((i&1)==0) { hash^=((hash<<7)^(*str++)^(hash>>3)); } else { hash^=(~((hash<<11)^(*str++)^(hash>>5))); } } return(hash % M); } 
相關文章
相關標籤/搜索