C# Hashtable/Dictionary写入和读取对比详解

 更新时间:2020年6月25日 11:39  点击:1453

一: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());获得线程安全的对象。
当然因为各自电脑的情况不一样,可能会有部分误差。如有问题,敬请斧正。

[!--infotagslink--]

相关文章

  • c# 遍历 Dictionary的四种方式

    这篇文章主要介绍了c# 遍历 Dictionary的四种方式,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2020-12-08
  • C#中数组、ArrayList、List、Dictionary的用法与区别浅析(存取数据)

    在工作中经常遇到C#数组、ArrayList、List、Dictionary存取数据,但是该选择哪种类型进行存储数据呢?很迷茫,今天小编抽空给大家整理下这方面的内容,需要的朋友参考下吧...2020-06-25
  • c# 用Dictionary实现日志数据批量插入

    这篇文章主要介绍了c# 用Dictionary实现日志数据批量插入的步骤,帮助大家更好的理解和使用c#中的Dictionary类,感兴趣的朋友可以了解下...2021-02-01
  • C#中哈希表(Hashtable)的介绍及简单用法

    在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对...2020-06-25
  • 聊聊C# 中HashTable与Dictionary的区别说明

    这篇文章主要介绍了聊聊C# 中HashTable与Dictionary的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-19
  • C#将HashTable中键列表或值列表复制到一维数组的方法

    这篇文章主要介绍了C#将HashTable中键列表或值列表复制到一维数组中方法,涉及C#操作HashTable的相关技巧,需要的朋友可以参考下...2020-06-25
  • C#中Dynamic和Dictionary性能比较

    开发中需要传递变参,考虑使用 dynamic 还是 Dictionary,dynamic 的编码体验显著优于 Dictionary,如果性能差距不大的话,我会选择使用dynamic。下面通过本文给大家详细介绍下C#中Dynamic和Dictionary性能比较,一起看看吧...2020-06-25
  • Lua Table转C# Dictionary的方法示例

    这篇文章主要给大家介绍了关于Lua Table转C# Dictionary的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。...2020-06-30
  • c语言实现的hashtable分享

    哈希表效率高,众所周知。应用广泛,php中大部分存储使用的都是hashtable,包括变量,数组…如何使用c语言实现hashtable呢,现提供自己的思路,如有不妥之处,敬请赐教...2020-04-25
  • C#中哈希表(HashTable)用法实例详解(添加/移除/判断/遍历/排序等)

    这篇文章主要介绍了C#中哈希表(HashTable)用法,简单讲述了哈希表的原理并结合实例形式详细分析了C#针对哈希表进行添加、移除、判断、遍历、排序等操作的实现技巧,需要的朋友可以参考下...2020-06-25
  • 详解C#中HashTable的用法

    在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值...2020-06-25
  • 利用C语言实现HashTable

    根据KEY从hashtable中获取接点,步骤是先根据KEY计算hash值,然后从hashtable中找到指定的接点或者接点链表...2020-04-25
  • C#探秘系列(一)——ToDictionary,ToLookup

    这个系列我们看看C#中有哪些我们知道,但是又不知道怎么用,又或者懒得去了解的东西,比如这篇我们要介绍的toDictionary和ToLookup。...2020-06-25
  • ASP.NET Dictionary 的基本用法示例介绍

    ASP.NET中的Dictionary想必使用.net的朋友并不陌生吧,下面以示例的方式为大家介绍下其基本用法,感兴趣的朋友可以参考下...2021-09-22
  • C#实现自定义Dictionary类实例

    这篇文章主要介绍了C#实现自定义Dictionary类,较为详细的分析了Dictionary类的功能、定义及用法,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • 自写一个模仿Dictionary与Foreach的实现及心得总结

    利用闲暇时间自己写一个类模仿Dictionary实现,如果一个类进行foreach的话,该类必须实现IEnumerable,集合要支持foreach方式的遍历,必须实现IEnumerable接口,感兴趣的你可不要错过了哈...2021-09-22
  • C#中Dictionary的作用及用法讲解

    这篇文章主要介绍了C#中Dictionary的作用及用法讲解,本文还对dictionary类用什么接口实现、Dictionary的基本用法做了讲解,需要的朋友可以参考下...2020-06-25
  • C#中查找Dictionary中重复值的方法

    这篇文章主要介绍了C#中查找Dictionary中重复值的方法,有需要的朋友可以参考一下...2020-06-25
  • C#中HashTable的定义与使用方法

    Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,所以Hashtable可以支持任何类型的keyvalue键值对...2020-06-25
  • 遍历Hashtable 的几种方法

    方法一: IDictionaryEnumerator enumerator = thProduct.GetEnumerator(); while (enumerator.MoveNext()) { arrKey.Add("@"+enumerator.Key.ToString());...2020-06-25