深入解析Hashtable、Dictionary、SortedDictionary、SortedList

我们先看Hashtable

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适用于读取操作频繁,写入操作很少的操作类型。

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

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

Dictionary的插入算法:1、计算key的hash值,并且找到buckets中目标桶的链首索引,2、从链上依次查找是否key已经保存,3、如果没有的话,判断是否存在freeList,4、如果存在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)

深入解析Hashtable、Dictionary、SortedDictionary、SortedList

时间: 2024-10-05 04:13:01

深入解析Hashtable、Dictionary、SortedDictionary、SortedList的相关文章

c语言 &lt;除法散列法&gt; 高效 HashTable Dictionary

c语言 <除法散列法> 高效 HashTable Dictionary  ,不管集合大小,任意长度根据key查询都只是一次寻址左右,so 最快时间复杂度为O1! 先上代码,明天写原理注释! HashDictionary.h #define CM_STR_HASHFUNC_CONSTANT 31 #define KEYSIZE 40 struct Entry { int hashCode; int next; char key[KEYSIZE]; void* value; }; struct H

C#常用的集合类型(ArrayList类、Stack类、Queue类、Hashtable类、SortedList类)

1.ArrayList类 ArrayList类主要用于对一个数组中的元素进行各种处理.在ArrayList中主要使用Add.Remove.RemoveAt.Insert四个方法对栈进行操作.Add方法用于将对象添加到 ArrayList 的结尾处:Remove方法用于从 ArrayList 中移除特定对象的第一个匹配项:RemoveAt方法用于移除 ArrayList 的指定索引处的元素:Insert方法用于将元素插入 ArrayList 的指定索引处. 示例 ArrayList的使用 示例将介

C# 中的集合(Array/ArrayList/List&lt;T&gt;/HashTable/Dictionary)

C# 中的集合(Array/ArrayList/List<T>/HashTable/Dictionary) int [] numbers = new int[5]; // 长度为5,元素类型为 int.string[,] names = new string[5,4]; // 5*4 的二维数组byte[][] scores = new byte[5][]; // 长度为 5 的数组,元素为 byte的数组,元素数组的长度未知. 不同的格式:int[] numbers = new int[5]

数组、数组链表ArrayList和List、Dictionary、SortedList、Hashtable

using System; using System.Collections.Generic;//数值链表的头文件 using System.Linq; using System.Text; using System.Collections;//数值链表的头文件 namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int[] nmbers = new int[5]; string[,]

数据结构解析-HashTable

概要 HashTable也是散列表的一种实现,我们在上一篇解析了HashMap,在这里我们与HashMap做个对比,让你能清晰的了解两者的区别: 散列表 实现方式 数据安全 数据安全实现方式 key\value是否可为Null HashMap 数组+单向链表+红黑树 不安全 无 可为Null HashTable 数组+单向链表 安全 Synchronized 不可为 Null HashTable 1.继承关系 public class Hashtable<K,V> extends Dictio

repeater绑定数组、哈希表、字典 ArrayList/HashTable,Dictionary为datasource

原文发布时间为:2009-11-19 -- 来源于本人的百度文章 [由搬家工具导入] repeater绑定数组、哈希表、字典datasource为ArrayList/HashTable,Dictionary时,范例 Default7.aspx 前台页面:<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default7.aspx.cs" Inherits="Defaul

Hashtable Dictionary List 谁效率更高

一 前言 很少接触HashTable晚上回来简单看了看,然后做一些增加和移除的操作,就想和List 与 Dictionary比较下存数据与取数据的差距,然后便有了如下的一此测试, 当然我测的方法可能不是很科学,但至少是我现在觉得比较靠谱的方法.如果朋友们有什么好的方法,欢迎提出大家来交流下. 先来简单介绍这三个容器的各自特点吧  1 hashtable 散列表(也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构. 2 List<T> 是针对特定类型.任意长度的一

HashTable Dictionary HashMap

脑海中一直存在两个Hash,一个是HashMap另一个是HashTable,今天来总结一下两者的区别 HashTable和HashMap 相同点:表示根据键的哈希代码进行组织的键/值对的集合. 区别:HashMap在C#中不存在的,而是在Java中 1.C#每一个元素都是存储在DictionaryEntry对象中的键/值对,键不能为 null,但值可以. 2.在Java的HashMap中,null可以作为键,这样的键只有一个:可以有一个或多个键所对应的值为null.当get()方法返回null值

dataview,datdalist以及hashtable dictionary和FileStream和Stream

1.DataView是DataTable的表示,DataTable表里的记录是没有顺序的,但显示可以有不同顺序(DataVIew), 但还是同一张表,所以一个DataTable可以有多个DataView,默认访问DataTable,其实是访问他的 DefaultView.DataSet则是DataTable的集合,也可以有不止一个DataTable 2.DataView   是一张DataTable的虚拟视图   ,主要用来显示数据的   ,其实数据的更改都是发生在DataTable中. 如果以