深刻解析Hashtable、Dictionary、SortedDictionary、SortedList

咱们先看Hashtablehtml

MSDN的解释:表示键/值对的集合,这些键/值对根据键的哈希代码进行组织。算法

Hash算法是把任意长度的输入(又叫作预映射, pre-image),经过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间一般远小于输入的空间,不 同的输入可能会散列成相同的输出,而不可能从散列值来惟一的肯定输入值。 数组

Hashtable 对象由包含集合元素的存储桶组成。存储桶是 Hashtable 中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶 可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键。数据结构

Hashtable 类默认的装填因子是 1.0,但实际上它默认的装填因子是 0.72。全部从构造函数输入的装填因子,Hashtable 类内部都会将其乘以0.72。这是一个要求苛刻的数字, 某些时刻将装填因子增减 0.01, 可能你的 Hashtable 存取效率就提升或下降了 50%,其缘由是装填因子决定散列表容量,而散列表容量又影响 Key 的冲突概率,进而影响性能。0.72 是 Microsoft通过大量实验得出的一个比较平衡的值。函数

咱们看Hashtable的一些源码:性能

 

Hashtable .ctor

Hashtable 扩容是个耗时很是惊人的内部操做,它之因此写入效率仅为读取效率的 1/10 数量级,频繁的扩容是一个因素。当进行扩容时,散列表内部要从新 new 一个更大的数组,而后把原来数组的内容拷贝到新数组,并进行从新散列。如何 new这个更大的数组也有讲究。散列表的初始容量通常来说是个素数。当扩容时,新数组的大小会设置成原数组双倍大小的相近的一个素数。测试

 

HashTable数据结构存在问题:空间利用率偏低、受填充因子影响大、扩容时全部的数据须要从新进行散列计算。虽然Hash具备O(1)的数据检索效率,但它空间开销却一般很大,是以空间换取时间。因此Hashtable适用于读取操做频繁,写入操做不多的操做类型。spa

Dictionary<K, V> 也是用的Hash算法,经过数组实现多条链式结构。不过它是采用分离连接散列法。采用分离连接散列法不受到装填因子的影响,扩容时原有数据不须要从新进行散列计算。code

采用分离连接法的 Dictionary<TKey, TValue> 会在内部维护一个链表数组。对于这个链表数组 L0,L1,...,LM-1, 散列函数将告诉咱们应当把元素 X 插入到链表的什么位置。而后在 find 操做时告诉咱们哪个表中包含了 X。 这种方法的思想在于:尽管搜索一个链表是线性操做,但若是表足够小,搜索很是快(事实也的确如此,同时这也是查找,插入,删除等操做并不是老是 O(1) 的缘由)。特别是,它不受装填因子的限制。
这种状况下,常见的装填因子是 1.0。更低的装填因子并不能明显的提升性能,但却须要更多的额外空间。 htm

Dictionary的插入算法:一、计算key的hash值,而且找到buckets中目标桶的链首索引,二、从链上依次查找是否key已经保存,三、若是没有的话,判断是否存在freeList,四、若是存在freeList,从freeList上摘下结点保存数据,不然追加在count位置上。

buckets数组保存全部数据链的链首,Buckets[i]表示在桶i中数据链的链首元素。entries结构体数组用于保存实际的数据,经过next值做为链式结构的向后索引。删除的数据空间会被串入到freeList链表的首部,当再次插入数据时,会首先查找freeList链表,以提升查找entries中空闲数据项位置的效率。在枚举器中,枚举顺序为entries数组的下标递增顺序。

 而SortedDictionary,MSDN是这样描述的:

SortedDictionary<(Of <(TKey, TValue>)>) 泛型类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数。就这一点而言,它与 SortedList<(Of <(TKey, TValue>)>)  泛型类类似。这两个类具备类似的对象模型,而且都具备 O(log n) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度: 

  1. SortedList<(Of <(TKey, TValue>)>)  使用的内存比 SortedDictionary<(Of <(TKey, TValue>)>) 少。
  2. SortedDictionary<(Of <(TKey, TValue>)>) 可对未排序的数据执行更快的插入和移除操做:它的时间复杂度为 O(log n),而 SortedList<(Of <(TKey, TValue>)>) 为 O(n)。
  3. 若是使用排序数据一次性填充列表,则 SortedList<(Of <(TKey, TValue>)>) 比 SortedDictionary<(Of <(TKey, TValue>)>) 快。

SortedDictionary<K, V>是按照K有序排列的(K, V)数据结构,以红黑树做为内部数据结构对K进行排列保存– TreeSet<T>,红黑树是一棵二叉搜索树,每一个结点具备黑色或者红色的属性。它比普通的二叉搜索树拥有更好的平衡性。2-3-4树是红黑树在“理论”上的数据结构。

2-3-4树插入算法:相似于二叉搜索树的插入(插入数据插入到树的叶子结点) ,若是插入位置是2-结点或者3-结点,那么直接插入到当前结点,若是插入位置是4-结点,须要将当前的4-结点进行拆分,而后再执行后继的插入操做。 

咱们来测试一下Hashtable、Dictionary和SortedDictionary的插入和查找性能。

 

性能测试代码

最终结果如图:

  

 

(原文:http://www.cnblogs.com/moozi/archive/2010/05/23/1741980.html)

相关文章
相关标签/搜索