任何活对象(哈希表)的哈希函数?

时间:2011-09-30 14:15:09

标签: c# c#-4.0 hash c#-3.0 hashmap

不确定它是否合理地重新打开了Hashing URL的早期主题。 尽管如此,我仍然很想知道这项工作是如何进行的。

假设:我们有一个哈希表,其中n(其中n< Infinity)元素的渐近时间复杂度为o(1);我们(CLR)在应用一些散列函数(Hn-1散列函数,其中n> 1)时实现了这一点。

问题:当我们寻找(检索)任何元素(如果使用不同的散列函数)时,有人可以解释一下CLR映射如何键入哈希码? CLR如何跟踪(如果是)任何活动对象(哈希表)的哈希函数?

提前致谢。

4 个答案:

答案 0 :(得分:1)

哈希码不能唯一标识对象。它只是用来快速将该对象放入桶中。一个存储桶中的元素可能但不必相等,但不同存储桶中的元素必须不相等。

从概念上讲,您可以将引用类型的默认GetHashCode()实现视为在每个实例中使用一个字段,该字段包含在对象创建时初始化的哈希码的随机值。实际的实现有点复杂,但这并不重要。

由于只有20亿个不同的哈希码,如果你有更多的元素,大多数哈希表实现的O(1)运行时将会崩溃。当然,分发必须是好的,即一定不能有太多的哈希冲突,但有一些不是大问题。


对于具有值语义的类型,您始终覆盖EqualsGetHashCode以使用确定相等的字段。

答案 1 :(得分:1)

从概念上讲,有两个哈希函数。您可能已经猜到,第一个哈希函数是关键对象的GetHashCode方法。第二个哈希函数是第一个哈希函数返回的密钥的哈希值。

因此,设想一个容量为1,024项的哈希表,并且您将插入两个键:K1K2

K1.GetHashCode()返回1,023。 K2.GetHashCode()返回65,535

然后代码将返回的密钥除以散列表大小并取余数。因此,两个键都映射到哈希表中的位置1,023。

K1已添加到表格中。当需要添加K2时,会发生冲突。所以代码转向第二个哈希函数。第二个散列函数可能是某种类型的“位混合器”(通常是计算散列码的最后一个阶段),它使返回密钥中的位随机化。从概念上讲,代码看起来像这样:

int hashCode = K2.GetHashCode();
int slot = hashCode % 1024;
if (table[slot] != null)
{
    int secondHashCode = BitMixer(hashCode);
    slot = secondHashCode % 1024;
}

这里的要点是代码不必跟踪不同键的多个散列函数。它知道它可以调用Key.GetHashCode()来获取对象的哈希码。从那里,它可以调用自己的位混合器函数或函数来生成额外的哈希码。

答案 2 :(得分:0)

不确定我是否理解你的问题,但是.NET中的每个对象都实现了GetHashCode函数,该函数返回在字典/哈希表中可用(和使用)的哈希码,因此对象本身负责生成一个好的哈希码。

当然,由于哈希码是一个int,因此可能(并且将会)存在疑虑。冲突由字典/哈希表处理/解决。

答案 3 :(得分:0)

每个对象都实现GetHashCode()函数和Equals()函数。 这些的默认实现与对象引用相关。例如,a.Equals(b)将返回与object.ReferenceEquals(a,b)相同的内容。这意味着如果两个对象引用相同,那么它们的哈希代码也是如此。

有些情况下,您需要为Equals()函数提供不同的语义。在这些情况下,您必须维持合同,a.Equals(b)然后a.GetHashCode() == b.GetHashCode()

使用的哈希函数很多,每个函数都有自己的优点和缺点。有一个有用的解释here。使用的实际功能不是你应该担心的,在Hashtable中保持平均 o(1)查找时间最重要的是(理想情况下)确保将要插入的对象具有它们的GetHashCode()结果尽可能接近均匀分布。