C#知识点总结系列:1、C#中Hashtable、Dictionary详解以及写入和读取对比

简介:

在本文中将从基础角度讲解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());获得线程安全的对象。

  当然因为各自电脑的情况不一样,可能会有部分误差。如有问题,敬请斧正。



本文转自程兴亮博客园博客,原文链接:http://www.cnblogs.com/chengxingliang/archive/2013/04/15/3020428.html,如需转载请自行联系原作者

相关文章
|
2月前
|
存储 C#
33.c#:hashtable集合
33.c#:hashtable集合
16 1
|
6月前
|
存储 安全 搜索推荐
c#集合_键值对Dictionary & SortedList
在 C# 中,键值对是一种常见的数据结构,可以使用不同的集合类实现。以下是常用的键值对集合类::一种使用哈希表实现的键值对集合。它通过将键哈希为桶号,然后将值存储在桶中进行快速查找。:一种基于数组实现的键值对集合。它会将键值对按照键排序并存储在数组中,以支持快速访问、查找和枚举。:一种使用红黑树实现的键值对集合。它能够按照键的排序进行快速查找,也可以快速地插入和删除键值对,并且该树具备自平衡的特性,使得插入、删除和搜索性能都非常优秀。
74 1
|
2月前
|
开发框架 .NET C#
C# Dictionary<string, string> 对key做筛选
C# Dictionary<string, string> 对key做筛选
27 2
|
8月前
|
C#
C# Hashtable的用法
Hashtable的用法
|
8月前
|
C#
C#中字典Dictionary的用法详解
C#中字典Dictionary的用法详解
|
8月前
|
C#
C#由Dictionary赋值引发的对引用类型使用的思考
C#由Dictionary赋值引发的对引用类型使用的思考
|
10月前
|
C#
C#List与ArrayList,Hashtable与Dictionary总结
C#List与ArrayList,Hashtable与Dictionary总结
36 0
C#List与ArrayList,Hashtable与Dictionary总结
|
C# 数据库
Lua Table转C# Dictionary
Lua Table转C# Dictionary
90 0
C#编程-91:Hashtable查找汉字个数
C#编程-91:Hashtable查找汉字个数
C#编程-91:Hashtable查找汉字个数
C#编程-89:Hashtable添加键值和遍历
C#编程-89:Hashtable添加键值和遍历
C#编程-89:Hashtable添加键值和遍历