Dictionary(HashMap)的實現


 什么是哈希表?

  哈希表(Hash table,也叫散列表),是根據key而直接進行訪問的數據結構。也就是說,它通過把key映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。
 
為什么要了解字典類?
 
1.HashMap的性能最棒查找,添加,刪除的時間復雜度都是常數。

Data Structure

Add

Find

Delete

GetByIndex

 Array (T[])

O(n)

O(n)

O(n)

O(1)

 Linked list (LinkedList<T>)

O(1)

O(n)

O(n)

O(n)

 Resizable array list (List<T>)

O(1)

O(n)

O(n)

O(1)

 Stack (Stack<T>)

O(1)

-

O(1)

-

 Queue (Queue<T>)

O(1)

-

O(1)

-

 Hash table (Dictionary<K,T>)

O(1)

O(1)

O(1)

-

 Tree-based dictionary

 (SortedDictionary<K,T>)

  O(log n)  

  O(log n)  

  O(log n)  

-

 Hash table based set

 (HashSet<T>)

O(1)

O(1)

O(1)

-

 Tree based set

 (SortedSet<T>)

O(log n)

O(log n)

O(log n)

-

 
 
2.舉一反三。HashSet是基於HashMap來實現的,操作很簡單,更像是對HashMap做了一次“封裝”,而且只使用了HashMap的key來實現各種特性()
 
HashMap的原理?
 

  哈希表的做法其實很簡單,就是把key通過一個固定的算法函數即所謂的哈希函數轉換成一個整型數字,然后就將該數字對數組長度進行取余,取余結果就當作數組的下標,將value存儲在以該數字為下標的數組空間里。

    而當使用哈希表進行查詢的時候,就是再次使用哈希函數將key轉換為對應的數組下標,並定位到該空間獲取value,如此一來,就可以充分利用到數組的定位性能進行數據定位
put方法:
 
           
public V put(K key, V value) {
// 處理key為null,HashMap允許key和value為null
if (key == null)
return putForNullKey(value);
// 得到key的哈希碼
int hash = hash(key);
// 通過哈希碼計算出bucketIndex
int i = indexFor(hash, table.length);
// 取出bucketIndex位置上的元素,並循環單鏈表,判斷key是否已存在
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
// 哈希碼相同並且對象相同時
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
// 新值替換舊值,並返回舊值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
 
// key不存在時,加入新元素
modCount++;
addEntry(hash, key, value, i);
return null;
}
 
 數組的特點是:尋址容易,插入和刪除困難;而鏈表的特點是:尋址困難,插入和刪除容易。那么我們能不能綜合兩者的特性,做出一種尋址容易,插入刪除也容易的數據結構?答案是肯定的,這就是我們要提起的哈希表,哈希表有多種不同的實現方法,我接下來解釋的是最常用的一種方法——拉鏈法,我們可以理解為“鏈表的數組”。
 
與其他集合的比較:
1.特點比較:

 

有序否

允許元素重復否

Collection

List

Set

AbstractSet

HashSet

TreeSet

是(用二叉樹排序)

Map

AbstractMap

使用key-value來映射和存儲數據,Key必須惟一,value可以重復

HashMap

TreeMap

是(用二叉樹排序)

2.HashMap與Hashtable的區別:
HashMap是非synchronized,而Hashtable是synchronized(針對整張表的鎖,性能不佳),HashMap可以 可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。
3.由於HashMap不是線程安全的,在多線程環境中使用 ConcurrentHashMap。原因:其關鍵在於使用了鎖分離技術, ConcurrentHashMap使用鎖桶,默認將hash表分為16分桶,線程操作時鎖定一個桶,這樣,最多可以16個線程同時寫入。大大提升並發性。而讀方面,ConcurrentHashMap使用弱一致迭代器,當iterator被創建后數據改變時創新新的數據,完成后再將頭指針替換為新數據。這保證了寫的連續性和擴展性。
 
操作:
遍歷:
Map map = new HashMap();
  Iterator iter = map.entrySet().iterator();
  while (iter.hasNext()) {
  Map.Entry entry = (Map.Entry) iter.next();
  Object key = entry.getKey();
  Object val = entry.getValue();
  }
 
刪除:
我們可以發現Dictionary在添加,刪除元素按照如下方法進行:
通過Hash算法來計算到指定的Bucket上,碰撞到同一個Bucket槽上所有數據形成一個單鏈表
默認情況Entries槽中的數據按照添加順序排列
刪除的數據會形成一個 LinkedList的鏈表,添加數據的時候,優先向 LinkedList鏈表中添加數據, LinkedList為空則按照count依次排列。  HashMap在每個LinkedList節點中儲存鍵值對對象。
 
 
 
參考:
 
 
 
 
 
 
 
 
 


免責聲明!

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



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