1. 程式人生 > >HashSet/HashMap儲存過程、擴容、實現原理

HashSet/HashMap儲存過程、擴容、實現原理

論壇可以幫助程式設計師很快的提升自己

第一次看見這句話不以為然,因為多多少少逛過,感覺並沒有對自己多大幫助

慢慢逛論壇次數多了,感覺自己只是在打發時間,根本對自己沒有任何幫助。突發奇想不再逛首頁,而是通過各大板塊選自己最近學的知識來檢驗自己的學習。

------------------------------------------------------分割線-------------------------------------------------------

還好,發現了不錯的論壇,比如

Surrin1999發出的 關於HashSet的有序無序問題

nayi_224回覆的見解真的很到位,多的不說,

------------------------------------------------------分割線-------------------------------------------------------以下藍色字為JDK原始碼

HashSet是基於HashMap儲存的資料,結構是陣列 + 連結串列

預設容量static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

載入因子(用來擴容的) static final float DEFAULT_LOAD_FACTOR = 0.75f;

在底層儲存資料時,較為形象的畫出如下圖:

儲存過程:

擴容是在當前容量的基礎上增加一倍(newCap = oldCap << 1),在不超過最大容量 的前提下 static final int MAXIMUM_CAPACITY = 1 << 30;  // 1073741824

關於載入因子:

載入因子過小,會導致記憶體的浪費,也會導致rehash操作頻繁,降低效率

載入因子過大,會導致每個桶中的連結串列過長從而降低效率

從JDK1.8開始,為了減小擴容次數,同時也為了保證每一個桶中的查詢效率,在桶中元素超過8時(static final int TREEIFY_THRESHOLD = 8;),

採取紅黑樹結構,

               if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st  注意下標從0開始

                       treeifyBin(tab, hash);

關於紅黑樹,本人比較愚笨,不懂了。。。

關於指定初始容量:

 static final int tableSizeFor(int cap) {

        int n = cap - 1;

        n |= n >>> 1;

        n |= n >>> 2;

        n |= n >>> 4;

        n |= n >>> 8;

        n |= n >>> 16;

        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ?

MAXIMUM_CAPACITY : n + 1;

 }

以上是JDK中原始碼,計算結果可以藉助IDE進行,只需每次修改n結束後輸出即可,結論是:

指定初始容量X時,並且 2n-1 < x <=2n 那麼最終該集合的容量為2n。