簡單概念
在c#中,List是順序線性表(非鏈表),用一組地址連續的存儲單元依次存儲數據元素的線性結構。
哈希表也叫散列表,是一種通過把關鍵碼值映射到表中一個位置來訪問記錄的數據結構。c#中的哈希表有Hashtable,Dictionary,Hashtable繼承自Map,實現一個key-value映射的關系。Dictionary則是一種泛型哈希表,不同於Hashtable的key無序,Dictionary是按照順序存儲的。哈希表的特點是:1.查找速度快,2.不能有重復的key。
創建過程
在c#中,我們實例化list時,如果不指定容量,則內部會生成一個靜態的空數組,有添加操作時,實例化為一個長度為4的數組,滿了以后,自動擴充為兩倍的容量。
哈希表也是類似的情況,先默認生成一個長度為11的哈希表,滿后,自動添加,而添加規則是內部循環素數數組,稍大於當前的長度,比如15 ,則長度設定為17。在哈希表創建可分為確定哈希函數,解決哈希沖突兩個步驟。
實驗執行結果
下面進行兩個實驗,實驗一,比較Hashtable,Dictionary,List三者在不同長度時的創建速度,實驗二比較三者在不同時間時的查找速度。(實驗代碼在最后)
硬件:intel core 2 quad cpu @ 2.66GHZ,4GB內存。
軟件:windows 2008,2010 VS編譯環境。
表1.三者的創建時間
長度\類型 |
Hashtable |
Dictionary |
List |
1 |
0.001s |
0s |
0s |
10 |
0S |
0S |
0s |
100 |
0S |
0S |
0s |
1000 |
0.003s |
0.005s |
0.001s |
10000 |
0.0032s |
0.003s |
0.002s |
100000 |
0.038s |
0.042s |
0.002s |
1000000 |
0.520s |
0.512s |
0.015s |
3000000 |
1.807s |
1.441s |
0.042s |
6000000 |
3.752s |
2.952s |
0.087s |
8000000 |
4.744s |
3.740s |
0.102s |
表2.三者的查找時間
長度\類型 |
Hashtable |
Dictionary |
List |
1 |
0s |
0s |
0s |
10 |
0s |
0s |
0s |
100 |
0s |
0s |
0s |
1000 |
0s |
0s |
0s |
10000 |
0s |
0s |
0.001s |
100000 |
0s |
0s |
0.010s |
1000000 |
0s |
0s |
0.009s |
3000000 |
0s |
0s |
0.009s |
6000000 |
0s |
0s |
0.058s |
8000000 |
0s |
0s |
0.077s |
總結
實驗一表明:哈希表比list需要花費更多的時間建立數據結構,這是因為哈希表花費時間去解決哈希沖突,而list不需要。但需要注意的是建立操作只需要執行一次。
實驗二表明:哈希表的查找速度幾乎不需要花費時間,這是因為哈希表在添加一對元素(key-value)時,就已經記錄下value的位置,所以查找時就會非常的快。哈希的查找復雜度O(1),list 的查找復雜度是O(n)。
哈希表的高速查找是空間換時間的典型應用,前期的建立時間隨着數量級的增加而增加,后期的查找則永遠是O(1)。所以我們得出結論:如果面對海量數據,且需要大量搜索,那建議使用哈希表。而當面對小量數據(數量級由服務器決定)時,使用List更合適。
最后友情提醒:第一,雖然在查找上哈希占有優勢,但不足的是1.占有空間大,2.不能有重復健。第二,如果需要使用哈希表,建議多使用Dictionary。Dictionary的運行時間比hashtable稍快,而且Dictionary是類型安全的,這有助於我們寫出更健壯更具可讀性的代碼,省去我們強制轉化的麻煩。Dictionary是泛型的,當K或V是值類型時,其速度遠遠超過Hashtable。
- /*
- *Author: chao
- *Date:2012.3.27
- *Fun: Compare list with hash in c#
- */
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Collections;
- namespace hash_vs_list
- {
- class Program
- {
- const int MAX = 50000;
- static void Main(string[] args)
- {
- //hash_table
- Console.WriteLine("hash_table");
- TimeSpan hash_start = new TimeSpan(DateTime.Now.Ticks); //開始時間
- Hashtable h1 = new Hashtable();
- for (int i = 0; i < MAX; i++)
- h1.Add(i, i.ToString());
- TimeSpan hash_end = new TimeSpan(DateTime.Now.Ticks); //結束時間
- TimeSpan hash_diff = hash_start.Subtract(hash_end).Duration();// 計算時間差
- string hash_create_diff = hash_diff.TotalSeconds.ToString(); //
- //hashtable search
- hash_start = new TimeSpan(DateTime.Now.Ticks);
- string tmp = h1[0].ToString();
- hash_end = new TimeSpan(DateTime.Now.Ticks);
- hash_diff = hash_start.Subtract(hash_end).Duration();
- string hash_search_diff = hash_diff.TotalSeconds.ToString();
- Console.WriteLine("create:{0} search:{1}", hash_create_diff, hash_search_diff);
- Console.WriteLine();
- //dict
- Console.WriteLine("dictionary");
- Dictionary<int, string> dict = new Dictionary<int, string>();
- TimeSpan dict_start = new TimeSpan(DateTime.Now.Ticks);
- for (int i = 0; i < MAX; i++)
- {
- dict.Add(i, i.ToString());
- }
- TimeSpan dict_end = new TimeSpan(DateTime.Now.Ticks);
- TimeSpan dict_diff = dict_start.Subtract(dict_end).Duration();
- string dict_create_diff = dict_diff.TotalSeconds.ToString();
- //dict search
- dict_start = new TimeSpan(DateTime.Now.Ticks);
- tmp = dict[0];
- dict_end = new TimeSpan(DateTime.Now.Ticks);
- dict_diff = dict_start.Subtract(dict_end).Duration();
- string dict_search_diff = dict_diff.TotalSeconds.ToString();
- Console.WriteLine("create:{0} search:{1}", dict_create_diff, dict_search_diff);
- Console.WriteLine();
- //list create
- Console.WriteLine("list");
- TimeSpan list_start = new TimeSpan(DateTime.Now.Ticks);
- List<int> l1 = new List<int>();
- for (int i = 0; i < MAX; i++)
- l1.Add(i);
- TimeSpan list_end = new TimeSpan(DateTime.Now.Ticks);
- TimeSpan list_diff = list_start.Subtract(list_end).Duration();
- string list_create_diff = list_diff.TotalSeconds.ToString();
- //list foreach
- list_start = new TimeSpan(DateTime.Now.Ticks);
- foreach (int i in l1)
- {
- if (i == MAX)
- break;
- }
- list_end = new TimeSpan(DateTime.Now.Ticks);
- list_diff = list_start.Subtract(list_end).Duration();
- string list_foreach_diff = list_diff.TotalSeconds.ToString();
- Console.WriteLine("create:{0},foreach:{1}", list_create_diff, list_foreach_diff);
- Console.WriteLine();
- Console.Read();
- }
- }
- }