JDK1.8 HashMap為什么在鏈表長度為8的時候轉紅黑樹,為啥不能是9是10?


起因:

這個問題是在面試某公司的時候面試官提的問題,當時沒回答上來。歸根到底還是因為自己復習基礎的時候還不夠仔細,也缺乏思考。

首先

我覺得需要確認一下,是不是隨便什么情況下只要滿足了鏈表長度為8就轉紅黑樹呢?答案自然不是,為什么不是,看代碼:

    /**
     * Replaces all linked nodes in bin at index for given hash unless
     * table is too small, in which case resizes instead.
     */
    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        ......
    }

這是HashMap轉紅黑樹的方法代碼,可以看到,如果此時的HashMap的長度是小於MIN_TREEIFY_CAPACITY的或者為空,則進行擴容操作,而不是轉紅黑樹,這其實也是容易忽略的點。

為什么要轉紅黑樹?

回答自然很簡單,因為鏈表是取一個數需要遍歷鏈表,復雜度為O(N),而紅黑樹為O(logN)唄,那么問題來了

為什么不直接使用紅黑樹,而是要先使用鏈表實在不行再轉紅黑樹呢?

答案自然要在源碼和注釋里找:在HashMap類中第174行左右有描述:

     Because TreeNodes are about twice the size of regular nodes, we
     use them only when bins contain enough nodes to warrant use
     (see TREEIFY_THRESHOLD)

“因為樹節點的大小是鏈表節點大小的兩倍,所以只有在容器中包含足夠的節點保證使用才用它”,顯然盡管轉為樹使得查找的速度更快,但是在節點數比較小的時候,此時對於紅黑樹來說內存上的劣勢會

超過查找等操作的優勢,自然使用鏈表更加好,但是在節點數比較多的時候,綜合考慮,紅黑樹比鏈表要好。

為什么是8,而不是9不是10?

其實當時想回答面試官這是基於統計的結果,但是心里很虛還是沒有說,再回頭看看源碼的描述:

Ideally, under random hashCodes, the frequency of nodes in bins follows a Poisson distribution 
with a parameter of about 0.5 on average for the default resizing threshold of 0.75, although
with a large variance because of resizing granularity. Ignoring variance, the expected
occurrences of list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)).
The first values are:
0: 0.60653066 1: 0.30326533 2: 0.07581633 3: 0.01263606 4: 0.00157952 5: 0.00015795 6: 0.00001316 7: 0.00000094 8: 0.00000006 more: less than 1 in ten million

理想情況下,在隨機哈希碼下,哈希表中節點的頻率遵循泊松分布,而根據統計,忽略方差,列表長度為K的期望出現的次數是以上的結果,可以看到其實在為8的時候概率就已經很小了,再往后調整並

沒有很大意義。


免責聲明!

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



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