資料結構之「雜湊表」

清塵閒聊發表於2019-03-23

什麼是雜湊表?

雜湊表(Hash Table, 也叫雜湊表),是根據鍵(Key)來直接訪問在記憶體儲存位置的資料結構。它通過一個雜湊函式將所需要查詢的資料對映到一張雜湊表中,來提升查詢效率。
雜湊函式的實現方法:
1.取餘法
取關鍵字被某個不大於雜湊表表長的數除後所得的餘數為雜湊地址。
2.摺疊法
將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進位)作為雜湊地址。
3.平方取中法
取關鍵字平方後的中間幾位為雜湊地址。
4.直接定址法
取關鍵字或關鍵字的某個線性函式值為雜湊地址。

雜湊衝突

不管用什麼雜湊函式去計算雜湊地址,都是會產生雜湊衝突的,因此我們需要想辦法解決雜湊衝突,並且在設計雜湊函式時,儘可能減少雜湊衝突。
1.單獨的連結串列法
在雜湊表的後面單獨鏈上一個單連結串列來儲存衝突的元素,JDK 1.8 裡的 HashMap 就是選擇的這種方式解決衝突的,不過它對連結串列做了一層優化。當元素個數大於等於 8 時,會把連結串列轉換成紅黑樹,提升查詢效率。
2.線性探測法
當發生雜湊衝突時,逐個探測存放地址的表,直到查詢到一個空單元。這個方式不便於查詢,不建議使用。
3.建立一個公共溢位區
當發生雜湊衝突時,就把元素存入到公用的溢位區,查詢時遍歷溢位區。
從上面這幾種處理方法來說,還是連結串列法效率比較高,推薦使用。不過都有現成的工具類使用,因此只需要知道實現原理,最好自己可以去寫程式碼實現它。

雜湊表

雜湊表有什麼用?

雜湊表在日常開發中還是比較常用的,因為它最優的查詢時間複雜度是 O(1),當雜湊衝突比較嚴重的時候,查詢效率就相當於線性的,因此雜湊演算法直接影響到查詢的效率。

雜湊表怎麼實現的?

雜湊表的結構

public class HashMap<K,V> {
    //用節點陣列當作雜湊表
    Node<K,V>[] table;
    int size;
    //節點
    static class Node<K,V> {
        //雜湊值
        final int hash;
        //鍵
        final K key;
        //值
        V value;
        //雜湊值衝突時儲存
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }
}
複製程式碼

總結

雜湊表是一個鍵值對的儲存結構,並且根據鍵進行雜湊演算法找到對應的儲存位置。雜湊演算法會直接影響到雜湊表的查詢效率,一般選擇雜湊衝突小的實現方式,以便提升查詢效率。當雜湊衝突時,一般選擇連結串列來儲存衝突的元素,當衝突的元素增多時,可以採用紅黑樹來儲存,以提升查詢效率。JDK 1.8 版本的 HashMap,當連結串列個數大於等於 8 時,就是採用紅黑樹來儲存的。在知道元素個數時,初始化雜湊表時直接指定雜湊表大小,因為當元素達到雜湊表大小時,會做 resize 操作。當元素越來越多時,resize 是很耗時的,相當於重建雜湊表。因此直接指定雜湊表大小,減少 resize 次數以便提升插入效能。

相關文章