我一直在研究 .NET 字典的实现,因为我想了解是什么使字典 ContainsKey 和查找速度更快:http://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,15debc34d286fdb3
ContainsKey 函数基本上会导致下面列出的 FindEntry:
Buckets 是一个整数数组,Entry 是一个 Entry 对象数组,Entry 对象是包含 HashCode、TKey 和 TValue 的结构体。
所以我知道这个查找很快,因为它是一个简单的数组查找。
private int FindEntry(TKey key) {
if( key == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets != null) {
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
}
}
return -1;
}
不过我试图理解这两行:
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next)
1)如果我理解正确的话,0x7FFFFFFF是为了确保我们不会得到负值。那么第一行返回什么?它是一个简单的整数还是一个质数?
2)在第二行中为什么我们将i初始化为buckets[hashCode %buckets.Length]?
第一行返回哈希码,其中高位关闭以使数字为正。它不一定是素数。丢弃任何哈希中的数据是完全有效的。哈希值0
(常量零)始终是有效的散列。这就是为什么这个操作是安全的。
在第二行中,我们需要将哈希码映射到存储桶索引。任何确定性映射都可以。因此,我们再次通过减少可能值的数量来丢弃哈希中的信息。模运算符实现了相当统一的映射。其他映射也是可能的,例如(再次)简单地屏蔽位。
在.NET中Dictionary
类中的每个桶逻辑上都是一个链表的开始。int[] buckets
包含索引entries
用于存储在内部的链表的开头entries
.
由于性能原因,它很复杂。从逻辑上讲,buckets
可能是一个new LinkedList<Entry>[capacity]
。这会做同样的事情,但分配更多。
网上有一些文章是关于Dictionary
内部结构。我发现这个算法非常好而且聪明。它不需要负载因子。桌子可以满载。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)