C#中哈希表(HashTable)的用法詳解以及和Dictionary比較

[^1]轉載於:https://www.cnblogs.com/zk-zhou/p/6672494.html

  1. 哈希表(HashTable)簡述

在.NET Framework中,Hashtable是System.Collections命名空間提供的一個容器,用於處理和表現類似keyvalue的鍵值對,其中key通常可用來快速查找,同時key是區分大小寫;value用於存儲對應於key的值。Hashtable中keyvalue鍵值對均爲object類型,所以Hashtable可以支持任何類型的keyvalue鍵值對.

  1. 什麼情況下使用哈希表

(1)某些數據會被高頻率查詢
(2)數據量大
(3)查詢字段包含字符串類型
(4)數據類型不唯一

  1. 哈希表的使用方法

哈希表需要使用的namespace

using System.Collections;
using System.Collections.Generic;

哈希表的基本操作:

//添加一個keyvalue鍵值對:
HashtableObject.Add(key,value);

//移除某個keyvalue鍵值對:
HashtableObject.Remove(key);

//移除所有元素:           
HashtableObject.Clear(); 

// 判斷是否包含特定鍵key:
HashtableObject.Contains(key);

控制檯程序例子:

using System;
using System.Collections; //file使用Hashtable時,必須引入這個命名空間
class Program
{
  public static void Main()
  {
     Hashtable ht = new Hashtable(); //創建一個Hashtable實例
     ht.Add("北京", "帝都"); //添加keyvalue鍵值對
     ht.Add("上海", "魔都");
     ht.Add("廣州", "省會");
     ht.Add("深圳", "特區");

     string capital = (string)ht["北京"];
     Console.WriteLine(ht.Contains("上海")); //判斷哈希表是否包含特定鍵,其返回值爲true或false
     ht.Remove("深圳"); //移除一個keyvalue鍵值對
     ht.Clear(); //移除所有元素
  }
}

哈希表中使用多種數據類型的例子:

using System;
using System.Collections;

class Program
{
    static Hashtable GetHashtable()
    {
      Hashtable hashtable = new Hashtable();
    
      hashtable.Add("名字", "小麗");
      hashtable.Add("年齡", 22);
      return hashtable;
    }

    static void Main()
    {
      Hashtable hashtable = GetHashtable();

      string name = (string)hashtable["名字"];
      Console.WriteLine(name);

      int age = (int)hashtable["年齡"];
      Console.WriteLine(age);
    }
}

當獲取哈希表中數據時,如果類型聲明的不對,會出現InvalidCastException錯誤。使用as-statements可以避免該錯誤。

using System;
using System.Collections;
using System.IO;

class Program
{
    static void Main()
    {
    Hashtable hashtable = new Hashtable();
    hashtable.Add(100, "西安");

    // 能轉換成功
    string value = hashtable[100] as string;
    if (value != null)
    {
        Console.WriteLine(value);
    }

    // 轉換失敗,獲取的值爲null,但不會拋出錯誤。
    StreamReader reader = hashtable[100] as StreamReader;

    if (reader == null)
    {
         Console.WriteLine("西安不是StreamReader型");
    }

    // 也可以直接獲取object值,再做判斷
    object value2 = hashtable[100];
    if (value2 is string)
    {
        Console.Write("這個是字符串型: ");
        Console.WriteLine(value2);
    }
    }
}
  1. 遍歷哈希表

遍歷哈希表需要用到DictionaryEntry Object,代碼如下:

for(DictionaryEntry de in ht) //ht爲一個Hashtable實例
{
Console.WriteLine(de.Key); //de.Key對應於keyvalue鍵值對key
Console.WriteLine(de.Value); //de.Key對應於keyvalue鍵值對value
}

遍歷鍵

foreach (int key in hashtable.Keys)
{
Console.WriteLine(key);
}

遍歷值

foreach (string value in hashtable.Values)
{
Console.WriteLine(value);
}

  1. 對哈希表進行排序

對哈希表按key值重新排列的做法:

ArrayList akeys=new ArrayList(ht.Keys);
akeys.Sort(); //按字母順序進行排序
foreach(string key in akeys)
{
Console.WriteLine(key + ": " + ht[key]); //排序後輸出
}

  1. 哈希表的效率

System.Collections下的哈希表(Hashtable)和System.Collections.Generic下的字典(Dictionary)都可用作lookup table,下面比較一下二者的執行效率。

Stopwatch sw = new Stopwatch();
Hashtable hashtable = new Hashtable();
Dictionary<string, int> dictionary = new Dictionary<string, int>();
int countNum = 1000000;

sw.Start();
for (int i = 0; i < countNum; i++)
{
    hashtable.Add(i.ToString(), i);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);  //輸出: 744

sw.Restart();
for (int i = 0; i < countNum; i++)
{
    dictionary.Add(i.ToString(), i);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);  //輸出: 489

sw.Restart();
for (int i = 0; i < countNum; i++)
{
    hashtable.ContainsKey(i.ToString());
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);  //輸出: 245

sw.Restart();
for (int i = 0; i < countNum; i++)
{
    dictionary.ContainsKey(i.ToString());
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);  //輸出: 192

由此可見,添加數據時Hashtable快。頻繁調用數據時Dictionary快。

結論:Dictionary<K,V>是泛型的,當K或V是值類型時,其速度遠遠超過Hashtable。

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

幾種C#框架提供的數據結構對單值查找的效率比較->http://www.cnblogs.com/eaglet/archive/2008/10/23/1317893.html
我個人是覺得,無論什麼時候,都應該使用Dictionary<K,V>,理由如下:
1、Dic是類型安全的,這有助於我們寫出更健壯更具可讀性的代碼,而且省卻我們強制轉化的麻煩。這個相信大家都明白。
2、Dic是泛行的,當K或V是值類型時,其速度遠遠超過Hashtable。這個大家對值類型與引用類型有所瞭解的話也會明白。

原因:Dictionary 類與 Hashtable 類的功能相同。對於值類型,特定類型(不包括 Object)的 Dictionary 的性能優於 Hashtable,這是因爲 Hashtable 的元素屬於 Object 類型,所以在存儲或檢索值類型時通常發生裝箱和取消裝箱操作。
3、如果K和V都是引用類型,如eaglet所測,Hashtable比Dic更快,這裏我要指出,eaglet所做的測試是有問題的。原因在於Hashtable與Dic採用的是不同的數據結構。eaglet的“Dictionary 由於在Hashtable基礎上封裝了一層”這個說法是不對的。

Dictionary 調用 Add 方法之前使用 ContainsKey 方法測試某個鍵是否存在,否則得到一個KeyNotFoundException。
當程序頻繁嘗試字典中不存在的鍵時,使用 TryGetValue 方法來檢索值,這種方法是一種更有效的檢索值的方法。

http://www.cnblogs.com/lucifer1982/archive/2008/06/18/1224319.html
http://www.cnblogs.com/lucifer1982/archive/2008/07/03/1234431.html

Hashtable在指定capacity參數時,它並不只開出capacity個槽的內存空間,而是開出比 capacity / 0.72(默認裝填因子) 大的最小素數個槽的空間;而Dic在指定capacity時,是開出 比capacity 大的最小素數個槽的空間。因此可以看到,樓主雖然都指定capacity爲10萬,而實際上Hashtable的槽的總數遠遠大於Dic的槽的總數,也就是佔用的內存遠遠大於Dic,因此,如此測試是不公平不公正的,如要公平公正的測試,則應該把Dic的capacity指定爲 10萬/0.72,請大家再測試其性能。

url:http://www.cnblogs.com/jhh0111/archive/2008/10/23/1318223.html

我認爲應該始終使用Dictionary<K, V>,即使要用Hashtable了,也可以用Dictionary<object, object>來替代。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章