淺析java8中HashMap的結構
阿新 • • 發佈:2019-02-12
HashMap中涉及的部分資料結構
陣列 陣列儲存區間是連續的,佔用記憶體嚴重,故空間複雜的很大。但陣列的二分查詢時間複雜度小,為O(1);陣列的特點是:定址容易,插入和刪除困難連結串列
連結串列儲存區間離散,佔用記憶體比較寬鬆,故空間複雜度很小,但時間複雜度很大,達O(N)。連結串列的特點是:定址困難,插入和刪除容易。雜湊表之拉鍊法
雜湊表(Hash table,也叫散列表),是根據關鍵碼值(Key-value)而直接進行訪問的資料結構。它通過把關鍵碼值對映到表中一個位置來訪問記錄,有點類似於陣列,並且能在O(1)(衝突情況另算)下查詢到元素。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表用拉鍊法實現的hashtable還可以理解為一個連結串列的陣列,因為該結構就是通過陣列+連結串列的組合來實現的,陣列的每個元素中都存放一個連結串列的頭結點。如下圖所示:
拉鍊法的具體實現是:將所有關鍵字為同義詞的結點連結在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指標組成的指標陣列t[0..m-1]。凡是雜湊地址為i的結點,均插入到以t為頭指標的單鏈表中。t中各分量的初值均應為空指標。在拉鍊法中,裝填因子α可以大於1,但一般均取α≤1。舉個栗子:
上圖是一個長度為16的陣列,每個元素儲存著一個連結串列的頭結點,元素儲存在陣列中的位置(index)是通過hash(key)%len獲得的,也就是用元素key的雜湊值對陣列長度取模得到的。例如陣列索引為12的這條記錄,12%16=12,28%16=12,108%16=12.140%16=12。所以12、28、108、140都儲存在陣列索引為12的位置。 HashMap其實也是一個線性的陣列,就如剛剛所言,他的實現可以理解為一個“連結串列的陣列”。而且HashMap裡面實現了一個Node作為一個基礎Bean,用來儲存HashMap中的內容。該Bean中重要的屬性有hash、key、value、next。部分原始碼如下:
static class Node<K,V> implements Map.Entry<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;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}