Dictionary<TKEY,TVALUE>计算key的哈希值使用的是取余法,这种方式可能会产生冲突,所以需要进行冲突解决。Dictionary<TKEY,TVALUE>解决冲突的方式是链接法。
我们可以根据源码来模拟推导一下这个过程:
当添加第一个元素时,此时会分配哈希表buckets数组和entries数组的空间和初始大小,默认为3。对key=1进行哈希求值,假设第一个元素的哈希值=9,然后targetBucket = 9%buckets.Length(3)的值为0,所以第一个元素应该放在entries数组的第一位。最后对哈希表buckets数组赋值,数组索引为0,值为0。此时内部结构如图所示:
然后插入第二个元素,对key=2进行哈希求值,假设第二个元素的哈希值=3,然后targetBucket = 3%buckets.Length (默认是3)的值为0,所以第二个元素应该放在entries数组的第一位。但是entries数组的第一位已经存在元素了,这就发生了冲突。Dictionary<TKEY,TVALUE>解决冲突的方式是链接法,把发生冲突的元素链接之前元素的后面,通过next属性来指定冲突关系,最后更新哈希表buckets数组。此时内部结构如图所示:
我们可以通过Dictionary<TKEY,TVALUE>查找元素的实现来证明我们上面的分析是正确的。
Dictionary<TKEY,TVALUE>查找元素的实现:
Dictionary<TKEY,TVALUE>之所以能实现快速查找元素,其内部使用哈希表来存储元素对应的位置,我们可以通过哈希值快速地从哈希表中定位元素所在的位置索引,从而快速获取到key对应的Value值。物极必反,Dictionary<TKEY,TVALUE>的缺点也很明显,就是里面的数据是无序排列的,所以按照一定顺序遍历查找数据效率是非常低的。
2.SortedDictionary<TKEY,TVALUE>SortedDictionary<TKEY,TVALUE>和Dictionary<TKEY,TVALUE>类似,至于区别我们从名称上就可以看出来,Dictionary<TKEY,TVALUE>是无序的,SortedDictionary<TKEY,TVALUE>则是有序的。key要保证唯一,而且还要有序排列,这让我们很自然的就想到了搜索二叉树。SortedDictionary<TKEY,TVALUE>使用一种平衡搜索二叉树——红黑树,作为存储结构。因为基于二分查找,所以添加、查找、删除元素的时间复杂度是O(log n)。相对于下面提到的SortedList<TKEY,TVALUE>来说,SortedDictionary<TKEY,TVALUE>在添加和删除元素时更快一些。如果想要快速查询的同时又能很好的支持排序的话,并且添加和删除元素也比较频繁,可以使用SortedDictionary<TKEY,TVALUE>。
SortedDictionary<TKEY,TVALUE>添加新元素的实现:
3.SortedList<TKEY,TVALUE>在既需要快速查找又需要顺序排列的场景下,Dictionary<TKEY,TVALUE>就无能为力了,因为Dictionary<TKEY,TVALUE>使用了散列函数,并不支持线性排序。我们可以使用SortedList<TKEY,TVALUE>集合类来应对这种场景。
SortedList<TKEY,TVALUE>集合内部是使用数组实现的,添加和删除元素的时间复杂度是O(n),查找元素利用了二分查找,所以查找元素的时间复杂度是O(log n)。所以SortedList<TKEY,TVALUE>虽然支持了有序排列,但是却是以牺牲查找效率为代价的。