【发布时间】:2010-11-27 07:29:39
【问题描述】:
字典中的散列过程是如何工作的?我读到使用字典可以更快地查找。但不明白怎么办?哈希和映射到索引是如何发生的?找不到任何好的参考。
编辑: 对象存储的实际内存位置是如何从哈希函数的结果中得到的?
【问题讨论】:
字典中的散列过程是如何工作的?我读到使用字典可以更快地查找。但不明白怎么办?哈希和映射到索引是如何发生的?找不到任何好的参考。
编辑: 对象存储的实际内存位置是如何从哈希函数的结果中得到的?
【问题讨论】:
哈希表或字典是一种存储键值对的数据结构。哈希表的优点是给定一个键找到相应的值非常快。简而言之,在哈希表中找到键值对的时间不取决于表的大小。将其与将键值对存储在列表或数组中进行比较。要查找键值对,您必须从头开始搜索列表,直到找到匹配的键。列表越长,查找键值对所需的时间就越多。使用 big-O 表示法,您可以说在哈希表中查找键的顺序为 O(1),而使用线性搜索在列表中查找键的顺序为 O(N)(简化)。
要在哈希表中插入键值对,您首先必须计算键的哈希码。在 .NET 中,所有对象都有一个名为 GetHashCode 的方法,该方法返回该特定对象的哈希码(32 位整数)。相等的对象返回相同的哈希码很重要,但如果不同的对象返回不同的哈希码也非常有用。请注意不同对象不能返回相同哈希码的误解——它们可以,但会导致冲突(见下文)。
以两个字符串的哈希码为例:
“嘘” 0x598FD95A "Foo" 0x598FD8DE尽管字符串非常相似,但它们具有不同的哈希码。
我在这里稍微简化一下,以专注于哈希表的重要方面,所以现在让我们说 Dictionary<TKey, TValue> 在内部将键值对存储在数组中。要在此数组中找到将存储键值对的索引,您必须以数组大小为模来计算键的哈希码。假设数组的大小为 5:
这导致了这个内部哈希表数组:
+---+----------+ | 0 | “福” | +---+----------+ | 1 | (空) | +---+----------+ | 2 | (空) | +---+----------+ | 3 | (空) | +---+----------+ | 4 | “嘘” | +---+----------+在哈希表中查找条目非常快。您只需计算键的哈希码,以内部数组的大小为模,然后检索该索引处的字符串。
现在考虑关键“动物园”:
索引(“动物园”)= 0x598FDC62 % 5 = 0它与键“Foo”具有相同的索引。这会导致所谓的冲突。哈希表的正确实现必须处理冲突,并且有different strategies for doing that。此外,随着内部数组被填满,数组中的空元素将越来越少,从而导致冲突数量增加。 负载因子是内部数组中已使用元素与总元素之间的比率。在上面的示例中,负载因子为 2/5 = 0.4。当负载因子超过某个阈值时,大多数哈希表实现都会增加内部数组的大小。
如果您想了解更多关于其中一些概念的信息,则必须研究其他答案中链接的一些更全面的资源。
【讨论】:
字典使用散列键进行查找,正如我在my answer to your other question 中解释的那样。因此,如果您有一个自定义对象类型作为键,那么一切都取决于您的自定义对象的 GetHashCode() 实现。
【讨论】:
字典中的散列过程使用一种称为链接的技术。 通过链接,使用辅助数据结构来保存任何冲突。具体来说,字典中的每个插槽都有一个映射到存储桶的元素数组。在发生碰撞时,碰撞元素会被添加到存储桶列表中。
有关详细信息,请参阅 MSDN 上的 this 文章。
【讨论】:
通常情况下,通过取散列值%数组大小,可能会产生冲突。
【讨论】: