C# Hashtable/Dictionary寫入和讀取對比詳解
一:HashTable
1.HashTable是一種散列表,他內(nèi)部維護很多對Key-Value鍵值對,其還有一個類似索引的值叫做散列值(HashCode),它是根據(jù)GetHashCode方法對Key通過一定算法獲取得到的,所有的查找操作定位操作都是基于散列值來實現(xiàn)找到對應的Key和Value值的。
2.我們需要使用一個算法讓散列值對應HashTable的空間地址盡量不重復,這就是散列函數(shù)(GetHashCode)需要做的事。
3.當一個HashTable被占用一大半的時候我們通過計算散列值取得的地址值可能會重復指向同一地址,這就是哈希沖突。
在.Net中鍵值對在HashTable中的位置Position= (HashCode& 0x7FFFFFFF) % HashTable.Length,.net中是通過探測法解決哈希沖突的,當通過散列值取得的位置Postion以及被占用的時候,就會增加一個位移x值判斷下一個位置Postion+x是否被占用,如果仍然被占用就繼續(xù)往下位移x判斷Position+2*x位置是否被占用,如果沒有被占用則將值放入其中。當HashTable中的可用空間越來越小時,則獲取得到可用空間的難度越來越大,消耗的時間就越多。
4.當前HashTable中的被占用空間達到一個百分比的時候就將該空間自動擴容,在.net中這個百分比是72%,也叫.net中HashTable的填充因子為0.72。例如有一個HashTable的空間大小是100,當它需要添加第73個值的時候?qū)U容此HashTable.
5.這個自動擴容的大小是多少呢?答案是當前空間大小的兩倍最接近的素數(shù),例如當前HashTable所占空間為素數(shù)71,如果擴容,則擴容大小為素數(shù)131.
二:Dictionary
1.Dictionary是一種變種的HashTable,它采用一種分離鏈接散列表的數(shù)據(jù)結(jié)構(gòu)來解決哈希沖突的問題。
2.分離鏈接散列表是當散列到同一個地址的值存為一個鏈表中。
3.這個變種HashTable的填充因子是1
三:本文將以代碼的形式探索HashTable和Dictionary的插入和三種讀取方式的效率(for/foreach/GetEnumerator)
public class HashTableTest
{
static Hashtable _Hashtable;
static Dictionary<string, object> _Dictionary;
static void Main()
{
Compare(10);
Compare(10000);
Compare(5000000);
Console.ReadLine();
}
public static void Compare(int dataCount)
{
Console.WriteLine("-------------------------------------------------\n");
_Hashtable = new Hashtable();
_Dictionary = new Dictionary<string, object>();
Stopwatch stopWatch = new Stopwatch();
//HashTable插入dataCount條數(shù)據(jù)需要時間
stopWatch.Start();
for (int i = 0; i < dataCount; i++)
{
_Hashtable.Add("Str" + i.ToString(), "Value");
}
stopWatch.Stop();
Console.WriteLine(" HashTable插入" + dataCount + "條數(shù)據(jù)需要時間:" + stopWatch.Elapsed);
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < dataCount; i++)
{
_Dictionary.Add("Str" + i.ToString(), "Value");
}
stopWatch.Stop();
Console.WriteLine(" Dictionary插入" + dataCount + "條數(shù)據(jù)需要時間:" + stopWatch.Elapsed);
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
int si = 0;
stopWatch.Start();
for(int i=0;i<_Hashtable.Count;i++)
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用for方式");
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
si = 0;
stopWatch.Start();
foreach (var s in _Hashtable)
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用foreach方式");
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
si = 0;
stopWatch.Start();
IDictionaryEnumerator _hashEnum = _Hashtable.GetEnumerator();
while (_hashEnum.MoveNext())
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用HashTable.GetEnumerator()方式");
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
si = 0;
stopWatch.Start();
for(int i=0;i<_Dictionary.Count;i++)
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用for方式");
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
si = 0;
stopWatch.Start();
foreach (var s in _Dictionary)
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用foreach方式");
//Dictionary插入dataCount條數(shù)據(jù)需要時間
stopWatch.Reset();
si = 0;
stopWatch.Start();
_hashEnum = _Dictionary.GetEnumerator();
while (_hashEnum.MoveNext())
{
si++;
}
stopWatch.Stop();
Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷采用Dictionary.GetEnumerator()方式");
Console.WriteLine("\n-------------------------------------------------");
}
}
四:從上面的結(jié)果可以看出
1.HashTable大數(shù)據(jù)量插入數(shù)據(jù)時需要花費比Dictionary大的多的時間。
2.for方式遍歷HashTable和Dictionary速度最快。
3.在foreach方式遍歷時Dictionary遍歷速度更快。
五:在單線程的時候使用Dictionary更好一些,多線程的時候使用HashTable更好。
因為HashTable可以通過Hashtable tab = Hashtable.Synchronized(new Hashtable());獲得線程安全的對象。
當然因為各自電腦的情況不一樣,可能會有部分誤差。如有問題,敬請斧正。
相關(guān)文章
C#中實現(xiàn)一次執(zhí)行多條帶GO的sql語句實例
這篇文章主要介紹了C#中實現(xiàn)一次執(zhí)行多條帶GO的sql語句,以實例形式較為詳細的分析了C#執(zhí)行sql語句的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09
C#如何優(yōu)雅的對WinForm窗體應用程序進行權(quán)限控制
經(jīng)常會出現(xiàn)winfrom頁面需要加載權(quán)限樹,下面這篇文章主要給大家介紹了關(guān)于C#如何優(yōu)雅的對WinForm窗體應用程序進行權(quán)限控制的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-11-11
C#設(shè)計模式之Mediator中介者模式解決程序員的七夕緣分問題示例
這篇文章主要介紹了C#設(shè)計模式之Mediator中介者模式解決程序員的七夕緣分問題,簡單說明了中介者模式的定義并結(jié)合七夕緣分問題實例分析了中介者模式的具體使用技巧,需要的朋友可以參考下2017-09-09

