C#中Hashtable、Dictionary詳解以及寫入和讀取對比

來源:互聯網
上載者:User

  在本文中將從基礎角度講解HashTable、Dictionary的構造和通過程式進行插入讀取對比。

  一:HashTable

    1.HashTable是一種散列表,他內部維護很多對Key-Value索引值對,其還有一個類似索引的值叫做散列值(HashCode),它是根據GetHashCode方法對Key通過一定演算法擷取得到的,所有的尋找操作定位操作都是基於散列值來實現找到對應的Key和Value值的。

    2.我們需要使用一個演算法讓散列值對應HashTable的空間地址盡量不重複,這就是散列函數(GetHashCode)需要做的事。

    3.當一個HashTable被佔用一大半的時候我們通過計算散列值取得的地址值可能會重複指向同一地址,這就是雜湊衝突。

    在.Net中索引值對在HashTable中的位置Position= (HashCode& 0x7FFFFFFF) % HashTable.Length,.net中是通過探測法解決雜湊衝突的,當通過散列值取得的位置Postion以及被佔用的時候,就會增加一個位移x值判斷下一個位置Postion+x是否被佔用,如果仍然被佔用就繼續往下位移x判斷Position+2*x位置是否被佔用,如果沒有被佔用則將值放入其中。當HashTable中的可用空間越來越小時,則擷取得到可用空間的難度越來越大,消耗的時間就越多。

    4.當前HashTable中的被佔用空間達到一個百分比的時候就將該空間自動擴容,在.net中這個百分比是72%,也叫.net中HashTable的填滿因數為0.72。例如有一個HashTable的空間大小是100,當它需要添加第73個值的時候將會擴容此HashTable.

    5.這個自動擴容的大小是多少呢?答案是當前空間大小的兩倍最接近的素數,例如當前HashTable所佔空間為素數71,如果擴容,則擴容大小為素數131.

          

  二:Dictionary

    1.Dictionary是一種變種的HashTable,它採用一種分離連結散列表的資料結構來解決雜湊衝突的問題。

    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條資料需要時間            stopWatch.Start();            for (int i = 0; i < dataCount; i++)            {                _Hashtable.Add("Str" + i.ToString(), "Value");            }            stopWatch.Stop();            Console.WriteLine(" HashTable插入" + dataCount + "條資料需要時間:" + stopWatch.Elapsed);            //Dictionary插入dataCount條資料需要時間            stopWatch.Reset();            stopWatch.Start();            for (int i = 0; i < dataCount; i++)            {                _Dictionary.Add("Str" + i.ToString(), "Value");            }            stopWatch.Stop();            Console.WriteLine(" Dictionary插入" + dataCount + "條資料需要時間:" + stopWatch.Elapsed);            //Dictionary插入dataCount條資料需要時間            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條資料需要時間            stopWatch.Reset();            si = 0;            stopWatch.Start();            foreach (var s in _Hashtable)            {                si++;            }            stopWatch.Stop();            Console.WriteLine(" HashTable遍曆時間:" + stopWatch.Elapsed + " ,遍曆採用foreach方式");            //Dictionary插入dataCount條資料需要時間            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條資料需要時間            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條資料需要時間            stopWatch.Reset();            si = 0;            stopWatch.Start();            foreach (var s in _Dictionary)            {                si++;            }            stopWatch.Stop();            Console.WriteLine(" Dictionary遍曆時間:" + stopWatch.Elapsed + " ,遍曆採用foreach方式");            //Dictionary插入dataCount條資料需要時間            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-------------------------------------------------");        }    }

  

  四:從上面的結果可以看出

    1.HashTable大資料量插入資料時需要花費比Dictionary大的多的時間。

    2.for方式遍曆HashTable和Dictionary速度最快。

    3.在foreach方式遍曆時Dictionary遍曆速度更快。

  五:在單線程的時候使用Dictionary更好一些,多線程的時候使用HashTable更好。

    因為HashTable可以通過Hashtable tab = Hashtable.Synchronized(new Hashtable());獲得安全執行緒的對象。

  當然因為各自電腦的情況不一樣,可能會有部分誤差。如有問題,敬請斧正。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.