由GetHashCode,所思C#中HashTable和Dictionary的区别和联系

1 篇文章 0 订阅
1 篇文章 0 订阅

1、在用dotPeek看.net源码的时候,发现了Boolean和Byte、Char等各基础类型的重写的GetHashCode的重写都不一样,对这个函数又不是很了解,所以查阅了一番资料,收货颇丰。

首先查看了https://www.cnblogs.com/tonytonglx/articles/2080438.html

作者与我的疑问类似,大概有两点:

(1)、为什么重写了Equals方法还要同时重写GetHashCode方法?

(2)、哈希码用在Hashtable和Dictionary中用于索引项,为何Hashtable和Dictionary的插入与检索效率不一致呢?

        对于第一点,参考了另一位大牛的博文,首先GetHashCode函数一般是在操作HashTable或者Dictionary之类的数据集的时候被调用,目的是产生一个Key,为了方便在 HashTable或者 Dictionary中的检索。 每个类型,不管是值类型还是引用类型,都提供这个基本函数,同样也可以像重写ToString或者Equals函数一样去重写它。但是不建议重写此函数,而且在使用这个函数也需要加倍小心。其次,为什么重写了Equals后也要重写GetHashCode,理由很简单,我理解的是,如果只重写Equals而不重写GetHashCode,很可能会产生哈希冲突,哈希冲突的意思大概就是当一个HashTable被占用一大半的时候我们通过计算散列值取得的地址值可能会重复指向同一地址。那就很危险了,检索一个item,出来俩结果。

        而为什么不重写GetHashCode有可能会产生哈希冲突,请参考https://blog.csdn.net/cnhk1225/article/details/23391885,不在详细说明。

      那对于第一个问题,就解释完了,至于怎么样重写,才能有效的避免哈希冲突,我觉得有兴趣的同学可以参考一下C# HashTable和Dictionary的GetHashCode函数(毕竟巨硬已经开源了.net了),在此想说的一点是,避免哈希冲突应该是一个哈希算法的基本要求,但是不是一个“好”的哈希算法,还是应该去看这个算法的效率,由于能力有限,在此不再说明。

        下面解释第二个问题,首先,我是自己亲自做过这个测试的,先说一下结果,插入数据,Dictionary速度略快,检索数据,Dictionary略快,之前不是很理解其内部结构及其实现方法,经过查阅资料总结如下:

    (1)首先对于HashTable来说,在.Net中键值对在HashTable中的位置Position= (HashCode& 0x7FFFFFFF) % HashTable.Length,.net中是通过探测法解决哈希冲突的,当通过散列值取得的位置Postion以及被占用的时候,就会增加一个位移x值判断下一个位置Postion+x是否被占用,如果仍然被占用就继续往下位移x判断Position+2*x位置是否被占用,如果没有被占用则将值放入其中。当HashTable中的可用空间越来越小时,则获取得到可用空间的难度越来越大,消耗的时间就越多。这里要引入一个填充因子的概念,填充因子用于控制创建HashTbale时的填充率,HashTable的填充因子为0.72,比如有一个HashTable的空间大小是100,当它需要添加第73个值的时候将会扩容此HashTable.那么扩容到多少呢,我也查了一下资料,答案是当前空间大小的两倍最接近的素数,例如当前HashTable所占空间为素数71,如果扩容,则扩容大小为素数131。

       (2)那对于Dictionary来说,与HashTable有什么区别呢,其中影响插入速度的区别就是,Dictionary的填充因子虽然是1,不过它是采用分离链接散列法。采用分离链接散列法不受到填充因子的影响,扩容时原有数据不需要重新进行散列计算。所以插入大量数据的时候,Dictionary还是比Hashtable有时间上的优势;

        对比一下,HashTable就有了空间利用率偏低,受填充因子影响大(需要重新计算散列)的缺点;至于检索速度,为何HashTable略快目前还没有查到原因,还请各位大神指点一二。另,HashTable的Insert操作需要装箱拆箱,而Dictionary是有泛型优势的,某博主曾指出,Dic是泛型的,当K或V是值类型时,其速度远远超过Hashtable(https://www.cnblogs.com/jhh0111/archive/2008/10/23/1318223.html)。

        如此,为何还要使用HashTable呢,为何Dictionary不能完全代替HashTable呢?

        HashTable对比Dictionary有如下优点:

        (1)key,value均为object类型(此优点也是缺点),有人认为可以用Dictionary<object,object>代替;

        (2)在查询一个不存在的key的时候,会返回一个null,而dictionary会throw 一个expection;

        (3)默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized() 方法可以获得完全线程安全的类型,而Dictionary是非线程安全的;

        如有不当之处,还请各位大神指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值