首先看看散列算法是什么。
散列函数或散列算法,又称哈希函数,英语:Hash Function,是一种从任何一种数据中创建小的数字“指纹”
的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新
创建一个叫做散列值的指纹。散列值通常用来代表一个短的随机字母和数字组成的字符串。
所有散列函数都有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原
始输入也是不相同的。这个特性是散列函数具有确定性的结果,具有这种性质的散列函数称为单向散列函数。但另一方
面,散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的。但也可能不同,
这种情况称为“散列碰撞”,这通常是两个不同长度的散列值,刻意计算出相同的输出值。
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它
通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫
做散列表。
首先Dictionary<TKey,TValue>是泛型版本的Hashtable,两者都是使用hashtable实现的
(http://en.wikipedia.org/wiki/Hashtable)。其最大的不同在于处理冲突上。
Hashtable采用的是直接散列或者在散列的方式,简而言之就是,发生冲突的时候,通过查找下一个空位置以解
决冲突。而当元素越来越多的时候(接近)存储容量的时候,冲突的概率就极大的增加了,因此可以在某个界限的时候
扩容解决这个问题。(当我们知道元素大概数量是,我们也可以设置容量)。
扩容是个耗时非常惊人的内部操作,Hashtable 之所以写入效率仅为读取效率的 1/10 数量级, 频繁的扩容是一个因素
。当进行扩容时,散列表内部要重新 new 一个更大的数组,然后把原来数组的内容拷贝到新数组,并进行重新散列。如
何 new 这个更大的数组也有讲究。散列表的初始容量一般来讲是个素数。当扩容时,新数组的大小会设置成原数组双倍
大小的相近的一个素数。为了避免生成素数的额外开销,.NET 内部有一个素数数组,记录了常用到的素数(这里就不列
出,下面文章中可以看到)。
Dictionary<TKey,TValue>使用的则是链表式的冲突解决办法,就是将冲突元素以链表的方式存储与key关联。
这样就避免了扩容问题。
这里有几篇hashtable数据结构的文章
(http://www.cnblogs.com/lucifer1982/archive/2008/06/18/1224319.html)
(http://www.cnblogs.com/lucifer1982/archive/2008/07/03/1234431.html)
(http://blog.csdn.net/chartnie/article/details/6790521)
(http://blogs.msdn.com/b/kcwalina/archive/2004/08/06/210297.aspx)