1. 程式人生 > >.Net 中HashTable,HashMap 和 Dictionary《key,value》和List《T》和DataTable的比較

.Net 中HashTable,HashMap 和 Dictionary《key,value》和List《T》和DataTable的比較

參考資料

http://www.coding123.net/article/20120419/DataTable-IList-compare.aspx


首先:

(ling)在.Net  模仿java 的過程中   拋棄了 HashMap ,所以以後再去面試.Net的時候當別人問你HashTable 和HashMap 的區別的時候,請告訴他,C#.Net 中  沒有HashMap 

好接下來進入正題

.Net 中HashTable 和 Dictionary<key,value> 和List<T>的比較(不要問我怎麼和題目不一樣),本文只比較兩種資料型別在使用時 功能相近的情況,差別太大的 則不比較。

先來比較

(yi)HashTable    和Dic 

資料結構

Hashtable和Dictionary從資料結構上來說都屬於Hashtable(雜湊表),都是對關鍵字(鍵值)進行雜湊操作,將關鍵字雜湊到Hashtable的某一個槽位中去,不同的是處理碰撞的方法。雜湊函式有可能將不同的關鍵字雜湊到Hashtable中的同一個槽中去,這個時候我們稱發生了碰撞,為了將資料插入進去,我們需要另外的方法來解決這個問題。

採用連結串列法的是Dic    而採用開放定址法(open addressing)-中  雙重雜湊的方法的是 HashTable

至於這兩種資料結構的使用方法  請自行閱讀演算法導論   或者參照網上部落格

但從底層的資料結構可以發現

如果增刪的動作很多的話 推薦使用Dic  因為解決碰撞的方式  是List.Add

如果改動的動作很少  查詢的動作很多的話   則推薦 使用HashTable  因為對映查詢之後  只需要跳躍查詢到  碰撞後移動資料即可,另外當增加資料太多時,開放定址的擴容很耗費效能(請閱讀<演算法導論>)

Dic 和HashTable使用比較

1:單執行緒程式中推薦使用 Dictionary, 有泛型優勢, 且讀取速度較快, 容量利用更充分.
 2:多執行緒程式中推薦使用 Hashtable, 預設的 Hashtable 允許單執行緒寫入, 多執行緒讀取, 對 Hashtable 進一步呼叫  Synchronized() 方法可以獲得完全執行緒安全的型別. 而 Dictionary 非執行緒安全, 必須人為使用 lock 語句進行保護,  效率大減.
 3:

Dictionary 有按插入順序排列資料的特性 (注: 但當呼叫 Remove() 刪除過節點後順序被打亂), 因此在需要體現順序的情境中使用 Dictionary 能獲得一定方便. //Dic遍歷時  會採用插入時的遍歷,而hashTable 採用遍歷時 則是打亂的

Hashtable 類和 Dictionary<TKey, TValue> 泛型類實現 IDictionary 介面 
Dictionary<TKey, TValue> 泛型類還實現 IDictionary<TKey, TValue>泛型介面。
因此,這些集合中的每個元素都是一個鍵/值對。

Dictionary<TKey, TValue> 類與 Hashtable 類的功能相同
對於值型別,特定型別(不包括 Object)的 Dictionary<TKey, TValue> 的效能優於 Hashtable,這是因為 Hashtable 的元素屬於 Object  型別,所以在儲存或檢索值型別時通常發生裝箱和取消裝箱操作。

(er)Dic  和 List<T>

關於資料結構:

在前邊的比較已經介紹了Dic   那麼 List <T> 的資料結構是什麼樣子的:

List<T>是 ArrayList 的泛型等效類(繼承了泛型介面)

堆中的樣子是這樣的

我們為了討論遍歷時Dictionary和List的效率,有個高人寫了個程式碼,這是載圖

很明顯,LIST效率要好的多。

問題剖析

同樣是集合,為什麼效能會有這樣的差距。我們要從儲存結構和作業系統的原理談起。

首先我們清楚List<T>是對陣列做了一層包裝,我們在資料結構上稱之為線性表,而線性表的概念是,在記憶體中的連續區域,除了首節點和尾節點外,每個節點都有著其唯一的前驅結點和後續節點。我們在這裡關注的是連續這個概念。

而HashTable或者Dictionary,他是根據Key而根據Hash演算法分析產生的記憶體地址,因此在巨集觀上是不連續的,雖然微軟對其演算法也進行了很大的優化。

由於這樣的不連續,在遍歷時,Dictionary必然會產生大量的記憶體換頁操作,而List只需要進行最少的記憶體換頁即可,這就是List和Dictionary在遍歷時效率差異的根本原因。

所以根據value 的查詢  dic 的效率是高於 List 的 但是遍歷的話   則Dic 要差點。這就好比你要摘抄書裡邊的所有文字  是根據目錄 查一個找一篇文章 快,還是直接從正文開始 從頭到尾快遍歷快一樣。單獨的找某一篇知道題目(key)的文章 當然是從目錄快了

再談Dictionary

也許很多人說,既然Dictionary如此強大,那麼我們為什麼不用Dictionary來代替一切集合呢?

在這裡我們除了剛才的遍歷問題,還要提到Dictionary的儲存空間問題,在Dictionary中,除了要儲存我們實際需要的Value外,還需要一個輔助變數Key,這就造成了記憶體空間的雙重浪費。

而且在尾部插入時,List只需要在其原有的地址基礎上向後延續儲存即可,而Dictionary卻需要經過複雜的Hash計算,這也是效能損耗的地方。

List<T>和 DataTable

DataTable,IList效能比較
1)二進位制序列化的情況

從測試結果可以看出,IList<T>序列化的檔案大小比DataTable小得多,這意味著在資料傳輸中頻寬佔用小很多,所以在設計Remoting介面時儘量使用IList<T>作返回值。

2)XML序列化的情況

從測試結果可以看出,IList<T>序列化後的檔案比同樣比DataTable小,但差距已經沒有二進位制序列化那麼明顯了。而且IList<T>的二進位制序列化和XML序列化相差很大,所以remoteing中建議使用二進位制序列化。

3)操作性比較

  DataTable有支援資料的提交、回滾、查詢等強大的方法,但訪問單元格內容的時候不方便,還要型別轉換。

  IList<T>則訪問項的屬性比較方便,有屬性自動提示,不用型別轉換,有LINQ的協助也能實現強大的查詢