1. 程式人生 > >數據結構與算法-hash表

數據結構與算法-hash表

數據結構與算法 技術分享 進行 return 等價 class 取值 href .cn

前言

哈希表是一種存放鍵-值對的數據結構,其中值用來存放我們真正需要的數據,鍵的主要目的就是為了找到值。哈希表理想情況下,只需要一次hash計算即可找到值數據,但通常情況下我們不需要耗費巨大的額外空間來追求這絲毫的查找速度(要追求低hash沖突率,必然要擴大hash表),我們更希望的是讓空間和時間達到某種平衡,這可以通過調節hash函數來解決(裝填因子)。

裝填因子=表中的記錄數/哈希表的長度,如果裝填因子越小,表明表中還有很多的空單元,則發生沖突的可能性越小;而裝填因子越大,則發生沖突的可能性就越大,在查找時所耗費的時間就越多(jdk中hashmap的默認裝填因子為0.75)。

hash函數

將字符串作為鍵的時候,我們可以將他作為一個大的整數,采用保留除余法。我們可以將組成字符串的每一個字符取值然後進行哈希,比如

public int getHashCode(string str)
{
    char[] s = str.toCharArray();
    int hash = 0;
    for (int i = 0; i < s.Length; i++)
    {
        hash = s[i] + (31 * hash); 
    }
    return hash;
}

上面的哈希值是Horner計算字符串哈希值的方法,公式為:

h = s[0] · 31L–1 + … + s[L – 3] · 312 + s[L – 2] · 311 + s[L – 1] · 310

舉個例子,比如要獲取字符串”call”的哈希值,字符串c對應的unicode為99,a對應的unicode為97,L對應的unicode為108,所以字符串”call”的哈希值為 3045982 = 99·313

+ 97·312 + 108·311 + 108·310 = 108 + 31· (108 + 31 · (97 + 31 · (99)))

對計算機而言,乘除是相當昂貴的計算,31*hash等價於hash<<5-hash,位運算要比乘除讓計算機更舒服。

避免哈希沖突

避免has沖突的方法有很多,但工程中常用到的是拉鏈法(Separate chaining with linked lists)。

如下圖,John Smith和Sandra Dee經過hash後都會映射在152的位置,這就產生了沖突,這裏通過將發生沖突的entry(key-value)串連起來解決(串連的方法有很多,最簡單的就是一個單鏈表,復雜一些的可以是二叉平衡樹,只要能夠進行有效查找的數據結構都可以)。

技術分享

數據結構與算法-hash表