HashMap—基本結構


前言


       數組的特點是:尋址容易,插入和刪除困難,數組利用下標定位,時間復雜度為O(1),插入或刪除元素的時間復雜度O(n)。

       鏈表的特點是:尋址困難,插入和刪除容易,鏈表定位元素時間復雜度O(n),插入或刪除元素的時間復雜度O(1)。

       那么我們能不能綜合兩者的特性,做出一種尋址容易,插入刪除也容易的數據結構?

       HashMap是結合兩者優勢,這是一種折中的方案。(在java8中引入了紅黑樹,是對性能的更進一步優化)

 

HashMap內部結構


HashMap實際上是一個數組,數組里面的每個元素都是一個鏈表。每個元素在通過put方法放入HashMap中的時候,要按照如下步驟進行:

1.根據該元素自身提供的hashcode計算出散列值,該散列值就是數組的下標

2.將新元素放入該數組位置的鏈表中

數組定義:

  1. /**
  2.      * The table, resized as necessary. Length MUST Always be a power of two.
  3.      */
  4. transient Entry[] table; 

      這是一個數組,transient關鍵字告訴我們它不會參與序列化。既然是一個數組,總有數目上限,也就意味着如果存入HashMap的元素太多,導致數組大小不能夠存放所有的鏈表的時候,數組大小必須要能夠調整。

Entry是什么類型?

 

 1 static class Entry<K,V> implements Map.Entry<K,V> {
 2         final K key;
 3         V value;
 4         Entry<K,V> next;
 5         final int hash;
 6 
 7         /**
 8          * Creates new entry.
 9          */
10         Entry(int h, K k, V v, Entry<K,V> n) {
11             value = v;
12             next = n;
13             key = k;
14             hash = h;
15         }
16         ....
17         public final boolean equals(Object o) {
18             if (!(o instanceof Map.Entry))
19                 return false;
20             Map.Entry e = (Map.Entry)o;
21             Object k1 = getKey();
22             Object k2 = e.getKey();
23             if (k1 == k2 || (k1 != null && k1.equals(k2))) {
24                 Object v1 = getValue();
25                 Object v2 = e.getValue();
26                 if (v1 == v2 || (v1 != null && v1.equals(v2)))
27                     return true;
28             }
29             return false;
30         }
31 
32         public final int hashCode() {
33             return (key==null   ? 0 : key.hashCode()) ^
34                    (value==null ? 0 : value.hashCode());
35         }
36         ....
Entry部分源碼

 

這是一個HashMap類的內部靜態類。實現了Map.Entry接口。接受兩個模板參數K和V。key和hash一旦在構造函數中被初始化,就不可改變,並且由於有next的存在,Entry可以構成一個單向鏈表。

HashMap 包含如下幾個構造器:

  1. HashMap():構建一個初始容量為 16,負載因子為 0.75 的 HashMap。

  2. ashMap(int initialCapacity):構建一個初始容量為 initialCapacity,負載因子為 0.75 的 HashMap。

  3. HashMap(int initialCapacity, float loadFactor):以指定初始容量、指定的負載因子創建一個 HashMap。

HashMap的基礎構造器HashMap(int initialCapacity, float loadFactor)帶有兩個參數,它們是初始容量initialCapacity和負載因子loadFactor。

負載因子loadFactor衡量的是一個散列表的空間的使用程度,負載因子越大表示散列表的裝填程度越高,反之愈小。對於使用鏈表法的散列表來說,查找一個元素的平均時間是O(1+a),因此如果負載因子越大,對空間的利用更充分,然而后果是查找效率的降低;如果負載因子太小,那么散列表的數據將過於稀疏,對空間造成嚴重浪費。

HashMap的實現中,通過threshold字段來判斷HashMap的最大容量:

threshold = (int)(capacity * loadFactor);

結合負載因子的定義公式可知,threshold就是在此loadFactor和capacity對應下允許的最大元素數目,超過這個數目就重新resize,以降低實的負載因子。默認的的負際載因子0.75是對空間和時間效率的一個平衡選擇。當容量超出此最大容量時, resize后的HashMap容量是原來容量的兩倍.

 

參考

http://www.codeceo.com/article/java-hashmap-learn.html

http://blog.csdn.net/csfreebird/article/details/7347026

http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html


免責聲明!

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



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