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());获得线程安全的对象。
当然因为各自电脑的情况不一样,可能会有部分误差。如有问题,敬请斧正。
【数据类型】Dictionary 与 ConcurrentDictionary 待续
Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射。通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary<TKey, TValue> 类是作为一个哈希表来实现的。检索速度取决于为 TKey 指定的类型的哈希算法的质量。TValue可以是值类型,数组,类或其他。
线程安全:CSDN上说法:
只要不修改该集合,Dictionary<TKey, TValue> 就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若允许多个线程对集合执行读写操作,您必须实现自己的同步。
读写并行的时候需要加锁,但是加上锁性能就会受影响。
ConcurrentDictionary<TKey, TValue> framework4出现的,可由多个线程同时访问,且线程安全。用法同Dictionary很多相同,但是多了一些方法。ConcurrentDictionary 属于System.Collections.Concurrent 命名空间按照CSDN上所说:System.Collections.Concurrent 命名空间提供多个线程安全集合类。当有多个线程并发访问集合时,应使用这些类代替 System.Collections 和 System.Collections.Generic 命名空间中的对应类型。
一 Dictionary使用
1)实例化 Dictionary<int, string> dic = new Dictionary<int, string>();
添加 dic.Add(1, "one");
提取: string a = dic[1]; //one
键不能重复,值可以重复。
排序: var dicNew=from d in dic order by d.key select d;
1、C#中Hashtable、Dictionary详解以及写入和读取对比的更多相关文章
- C#中Hashtable、Dictionary详解以及写入和读取对比
转载:http://www.cnblogs.com/chengxingliang/archive/2013/04/15/3020428.html 在本文中将从基础角度讲解HashTable.Dicti ...
- php中关于引用(&)详解
php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
- AngularJS select中ngOptions用法详解
AngularJS select中ngOptions用法详解 一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...
- 【转载】C/C++中extern关键字详解
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
- oracle中imp命令详解 .
转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...
- Android中Service(服务)详解
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- Android中mesure过程详解
我们在编写layout的xml文件时会碰到layout_width和layout_height两个属性,对于这两个属性我们有三种选择:赋值成具体的数值,match_parent或者wrap_conte ...
随机推荐
- [转载]使用iscroll.js-tab左右滑动导航--tab点击无效果
转载自:http://blog.csdn.net/zuoyiran520081/article/details/77369421 最近在页面中用iscroll.js,但是但是有跳转,用a标签的hre ...
- MySQL权限系统(一).The MySQL Access Privilege System 概述
纯属个人阅读,如有翻译错误,请指出 The primary function of the MySQL privilege system is to authenticate a user who c ...
- C++程序设计练习(一)
// 1. 在屏幕上输出内容 #include<iostream> using namespace std; int main(){ int i= 1; cout<<" ...
- 插入排序 Insertion Sort
插入排序算法的运作如下: 通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入. 插入排序算法的实现我放在这里. 时间/空间复杂度: 最差时间复杂度 O(n^2) 最优时间 ...
- js文件操作
IE下 1. 写入 FileSystemObject可以将文件翻译成文件流. 第一步: 例: 复制代码代码如下: Var fso=new ActiveXObject(Scripting.FileSys ...
- web测试点梳理
前言 前面一篇文章讲解了app测试一些功能点.那么相应的也梳理一下web测试相关的功能的测试点吧,此篇文章只是给你们一个思路,如果要涉及web端每个测试点,基本不可能实现的,所以只是提供一个设计的思路 ...
- 大数据架构之:Storm
Storm是一个免费开源.分布式.高容错的实时计算系统,Twitter开发贡献给社区的.Storm令持续不断的流计算变得容易,弥补了Hadoop批处理所不能满足的实时要求. Storm经常用 ...
- window7 3G/4G拨号操作
Win7系统Modem拨号操作指导:https://wenku.baidu.com/view/bb855b1dc77da26925c5b0e1.html 拨号上网设置APN,拨号号码,帐号和密码:ht ...
- 1.2CMM/CMMI是什么?
"CMM是指“能力成熟度模型”,其英文全称为Capability Maturity Model for Software,英文缩写为SW-CMM,简称CMM.它是对于软件组织在定义.实施.度 ...
- linux虚拟机ping通主机
右键虚拟机,选择网络适配器,设置为桥接模式.然后关闭主机防火墙,ping就行了(一直ping是没有参数的)