jdk1.8 HashMap底層數據結構:散列表+鏈表+紅黑樹(圖解+源碼)


一、前言

  本文由jdk1.8源碼整理而得,附自制jdk1.8底層數據結構圖,並截取部分源碼加以說明結構關系。

二、jdk1.8 HashMap底層數據結構圖

  

三、源碼

  1.散列表(Hash table,也叫哈希表):

    /**
     * 表,第一次使用時初始化(而非實例化集合時進行初始化),並根據需要調整大小。當分配時,長度總是2的冪。(在某些操作中,我們還允許長度為零,以允許當前不需要的引導機制。)
   */ transient Node<K,V>[] table;

  2.鏈表:

    /**
     * Basic hash bin node, used for most entries.  (See below for
     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
     */
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
     …… }

  3.紅黑樹:

    /**
     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
     * extends Node) so can be used as extension of either regular or
     * linked node.
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        ……
    }

四、問題探究

  1.散列表后面跟的“鏈表、紅黑樹”是怎么來的,都解決了哪些問題?

    答:

    ①鏈表的由來:Hash碰撞:不同的元素通過hash算法可能會得到相同的hash值,如果都放同一個桶里,后面放進去的就會覆蓋前面放的,所以為了解決hash碰撞時元素被覆蓋的問題,就有了在桶里放鏈表。

    ②紅黑樹的由來:假設現在HashMap集合中大多數的元素都放到了同一個桶里(由hash值計算而得的桶的位置相同),那么這些元素就在這個桶后面連成了鏈表。現在需要查詢某個元素,那么此時的查詢效率就很慢了,它是在做鏈表查詢( O(N) 的查詢效率)。為了解決這個問題,就引入了紅黑樹( log(n) 的查詢效率):當鏈表到達一定長度時就在鏈表的后面創建紅黑樹。

    ③其實,“盡量避免hash 沖突,讓元素較為均勻的放置到每個桶”才是查詢效率最高的( O(1) 的查詢效率),這和hash算法的實現息息相關,這里不做深究。

  2.如圖可知,散列表后面跟的數據結構有可能是鏈表,也有可能是紅黑樹。散列表后面跟什么數據結構是怎么確定的?

    答:

    ①鏈表節點轉換成紅黑樹節點的閾值, 節點數 >= 8 就轉:

      static final int TREEIFY_THRESHOLD = 8;

    ②紅黑樹節點轉換鏈表節點的閾值, 節點數 <= 6 就轉:

      static final int UNTREEIFY_THRESHOLD = 6;

    ③轉紅黑樹時, table的最小長度:

      static final int MIN_TREEIFY_CAPACITY = 64;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM