1. 程式人生 > 其它 >C# Hashtable、HashSet和Dictionary的區別

C# Hashtable、HashSet和Dictionary的區別

1.Hashtable
  雜湊表(HashTable)表示鍵/值對的集合。在.NET Framework中,Hashtable是System.Collections名稱空間提供的一個容器,用於處理和表現類似key-value的鍵值對,其中key通常可用來快速查詢,同時key是區分大小寫;value用於儲存對應於key的值。Hashtable中key-value鍵值對均為object型別,所以Hashtable可以支援任何型別的keyvalue鍵值對,任何非 null 物件都可以用作鍵或值。

2.HashSet類

主要是設計用來做高效能集運算的,例如對兩個集合求交集、並集、差集等。集合中包含一組不重複出現且無特性順序的元素,HashSet拒絕接受重複的物件。

  HashSet的一些特性如下:

  a. HashSet中的值不能重複且沒有順序。

  b. HashSet的容量會按需自動新增。

3.Dictionary

他本身有集合的功能有時候可以把它看成陣列

  他的結構是這樣的:Dictionary<[key], [value]>

  他的特點是存入物件是需要與[key]值一一對應的存入該泛型

  通過某一個一定的[key]去找到對應的值

Hashtable 與 Dictionary

第一、儲存的資料型別

Hashtable不是泛型的,不是型別安全的;Dictionary是泛型的,是型別安全的;

Hashtable的鍵值都是Object型別的,但是Dictionary的鍵值的資料型別是可以指定的。

也就是說如果往Hashtable裡面存入Object以外的資料型別,則在取出該資料時,需要對其進行顯示的型別轉換,才能夠正常使用。而Dictionary則沒有這個問題。

從這方面講的話,Hashtable相當於Dictionary<Object,Object>

Hashtable ht =newHashtable();

Dictionary<string,int> dic =newDictionary<string,int>();

ht.Add("A", 1);

dic.Add("A", 1);

//Console.WriteLine(ht["A"]+1); //編譯錯誤!Object型別不能和int型別直接進行相加。

Console.WriteLine((int)ht["A"] + 1);//編譯通過,輸出結果為:2

Console.WriteLine(dic["A"] + 1);

第二、讀取資料的順序與新增資料的順序的一致性

Dictionary和Hashtable的讀取資料的順序和新增資料時的資料的順序的一致性均不能夠保證,或者可以說沒有一致性。

Dictionary在只新增不刪除的時候能夠保持讀取資料的順序和新增時候的順序是一致的;但是經過刪除和新增操作之後,就不能夠保證讀取資料的順序和新增時候的順序一致了。

Dictionary<int,int> dic =newDictionary<int,int>();

dic.Add(0, 0);

dic.Add(1, 1);

dic.Add(2, 2);

Console.WriteLine("僅僅經過新增元素處理之後:");

foreach(KeyValuePair<int,int> kvpindic)

{

Console.WriteLine("Key:"+ kvp.Key +" Value:"+ kvp.Value);

}

dic.Remove(0);

dic.Add(3, 3);

Console.WriteLine("經過刪除和新增元素處理之後:");

foreach(KeyValuePair<int,int> kvpindic)

{

Console.WriteLine("Key:"+ kvp.Key +" Value:"+ kvp.Value);

}

對於Dicitionary而言,如果從中刪除一個元素,則之後新新增的元素會填補這個被刪除元素的位置,因而致使新增資料的順序與讀取資料的順序是不一致的。

對於Hashtable而言,它的資料儲存順序是按一定的演算法算出來的,所以絕大多數情況下,它的資料讀取順序和資料新增順序是不一致的。

所以如果你需要保持資料新增時的順序的時候,最好不要用Dictionary和Hashtable。

第三、當用一個不存在的Key值到Hashtable或者Dictionary中取值時

對於Hashtable而言,如果用一個不存在的Key值進行取值的話,會返回一個null;

Hashtable ht =newHashtable();

Console.WriteLine(ht["b"]==null);

對於Dictionary而言,如果用一個不存在的Key值進行取值的話,會引發“System.Collections.Generic.KeyNotFoundException”型別的異常。

所以在從Dictionary或者Hashtable取值時,可以先判斷Key值是否存在(用ContainsKey()方法進行判斷),以防止出現預期以外的值或者異常。

第四、執行緒安全性

Dictionary不是執行緒安全的,Hashtable是執行緒安全的。對 Hashtable 進一步呼叫 Synchronized() 方法可以獲得完全執行緒安全的型別. 而 Dictionary 非執行緒安全, 必須人為使用 lock 語句進行保護, 效率大減。

HashSet代替List問題

NET3.5多了個HasSet<T>用來儲存集合。從名稱可以看出,它是基於Hash的。可以簡單理解為沒有Value的Dictionary<TKey,TValue>。

HashSet<T>不能用索引訪問,不能儲存重複資料,元素T必須正確實現了Equals和GetHashCode。

那它的優勢是什麼呢?

檢索的效能。簡單的說它的Contains方法的效能在大資料量時比List<T>好得多。HashSet<T>的Contains方法複雜度是O(1),List<T>的Contains方法複雜度是O(n)。

那麼,在集合的目的是為了檢索的情況下,我們應該使用HashSet<T>代替List<T>。比如一個儲存關鍵字的集合,執行的時候通過其Contains方法檢查輸入字串是否關鍵字。

HashSet<T>是專門設計用來做集合運算(取交集,並集等),所以提供了UnionWith、IntersectWith等方法。

另:如果資料量很小,那麼任然推薦使用List<T>。
這個“小”是多小呢?其實是用Hashtable還是ListDictionary時存在同樣的取捨問題,.NET為其設計了HybridDictionary類實現一個混合容器,當數量小於等於8(目前是8,不保證微軟以後不會變)的時候,HybridDictionary內部使用ListDictionary,當數量大於8的時候,HybridDictionary內部使用Hashtable。所以,如果我們知道我們集合的數量不會大於8的話,就算目的是為了檢索,任然推薦使用List<T>。

由於 Hashtable 和 Dictionary 同時存在, 在使用場景上必然存在選擇性, 並不任何時刻都能相互替代.
[1] 單執行緒程式中推薦使用 Dictionary, 有泛型優勢, 且讀取速度較快, 容量利用更充分.
[2] 多執行緒程式中推薦使用 Hashtable, 預設的 Hashtable 允許單執行緒寫入, 多執行緒讀取, 對 Hashtable 進一步呼叫 Synchronized() 方法可以獲得完全執行緒安全的型別. 而 Dictionary 非執行緒安全, 必須人為使用 lock 語句進行保護, 效率大減.
[3] Dictionary 有按插入順序排列資料的特性 (注: 但當呼叫 Remove() 刪除過節點後順序被打亂), 因此在需要體現順序的情境中使用 Dictionary 能獲得一定方便.