1. 程式人生 > >ArrayMap和HashMap區別

ArrayMap和HashMap區別

如果 一定的 技術分享 pub ray aci 知識 處理 arraymap

什麽是Map?

Map的三個特點

1.包含鍵值對
2.鍵唯一
3.鍵對應的值唯一

一:

什麽是Hash

Hash,也可以稱為“散列”,就是把任意長度的輸入,通過散列算法,變換成固定長度的輸出,該輸出就是散列值。這是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出(也就是多對一的關系)。

HashMap

HashMap內部是使用一個默認容量為16的數組來存儲數據的,而數組中每一個元素卻又是一個鏈表的頭結點,所以,更準確的來說,HashMap內部存儲結構是使用哈希表的拉鏈結構(數組+鏈表),這種存儲數據的方法叫做拉鏈法 。如圖:

技術分享圖片

且每一個結點都是Entry類型,那麽Entry是什麽呢?我們來看看HashMap中Entry的屬性:

1 final K key;  
2 final V value;  
3 final int hash;  
4 HashMapEntry<K, V> next;  

從中我們得知Entry存儲的內容有key、value、hash值、和next下一個Entry,那麽,這些Entry數據是按什麽規則進行存儲的呢?就是通過計算元素key的hash值,然後對HashMap中數組長度取余得到該元素存儲的位置,計算公式為hash(key)%len,比如:假設hash(14)=14,hash(30)=30,hash(46)=46 我們對len取余,得到hash(14)%16=14,hash(30)%16=14,hash(46)%16=14。所以hash值為14的這個元素存儲在數組下標為14的位置。

從中可以看出,如果有多個元素key的hash值相同的話,後一個元素並不會覆蓋上一個元素,而是采取鏈表的方式,把之後加進來的元素加入鏈表末尾,從而解決了hash沖突的問題,由此我們知道HashMap中處理hash沖突的方法是鏈地址法。

在此補充一個知識點,處理hash沖突的方法有以下幾種:

  1. 開放地址法
  2. 再哈希法
  3. 鏈地址法
  4. 建立公共溢出區

講到這裏,重點來了,我們知道HashMap中默認的存儲大小就是一個容量為16的數組,所以當我們創建出一個HashMap對象時,即使裏面沒有任何元素,也要分別一塊內存空間給它,而且,我們再不斷的向HashMap裏put數據時,當達到一定的容量限制時(這個容量滿足這樣的一個關系時候將會擴容:HashMap中的數據量>容量*加載因子,而HashMap中默認的加載因子是0.75),HashMap的空間將會擴大,而且擴大後新的空間一定是原來的2倍,我們可以看put()方法中有這樣的一行代碼:

1 int newCapacity = oldCapacity * 2;

所以,只要一滿足擴容條件,HashMap的空間將會以2倍的規律進行增大。假如我們有幾十萬、幾百萬條數據,那麽HashMap要存儲完這些數據將要不斷的擴容,而且在此過程中也需要不斷的做hash運算,這將對我們的內存空間造成很大消耗和浪費,而且HashMap獲取數據是通過遍歷Entry[]數組來得到對應的元素,在數據量很大時候會比較慢,所以在Android中,HashMap是比較費內存的。

所以我們在一些情況下可以使用SparseArray和ArrayMap來代替HashMap。

二:

ArrayMap

ArrayMap是一個<key,value>映射的數據結構,它設計上更多的是考慮內存的優化,內部是使用兩個數組進行數據存儲,一個數組記錄key的hash值,另外一個數組記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,在添加、刪除、查找數據的時候都是先使用二分查找法得到相應的index,然後通過index來進行添加、查找、刪除等操作,所以,應用場景和SparseArray的一樣,如果在數據量比較大的情況下,那麽它的性能將退化至少50%。

ArrayMap方法:

public V put(K key, V value)

public V get(Objectkey)

public V remove(Objectkey)

public K keyAt(int index) 

public V valueAt(int index)

ArrayMap應用場景

  • 1.數據量不大,最好在千級以內
  • 2.數據結構類型為Map類型

ArrayMap和HashMap區別