常用hash演算法對比
我來做一個比喻吧。
我們有很多的小豬,每個的體重都不一樣,假設體重分佈比較平均(我們考慮到公斤級別),我們按照體重來分,劃分成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效果最差,但得分相似,其演算法本質是相似的。
在資訊修競賽中,要本著易於編碼除錯的原則,個人認為BKDRHash是最適合記憶和使用的