Hashtable碰撞重组 - 如何读取值?

时间:2012-02-06 20:49:33

标签: c# hashtable

我试图了解Hashtables在C#中的工作原理。我阅读了MSDN文章,我理解C#Hashtables使用'rehashing'进行冲突,即如果我尝试将键/值对插入哈希表,如果使用HashFunction H1导致冲突,那么它将尝试HashFunction H2,H3等等,直到找不到碰撞。

MSDN引用:

  

Hashtable类使用不同的技术   rehasing。 (有些消息来源称重新散列为双重散列。)

     

Rehashing的工作方式如下:有一组哈希不同   函数,H1 ... Hn,以及从中插入或检索项目时   哈希表,最初使用H1哈希函数。如果这导致   碰撞时,H2会被尝试,如果需要,可以直到Hn。   上一节只显示了一个哈希函数,即   初始哈希函数(H1)。其他哈希函数非常相似   对于此功能,仅通过乘法因子进行区分。在   一般来说,哈希函数Hk定义为:

     

Hk(key)= [GetHash(key)+ k *(1 +(((GetHash(key)>> 5)+ 1)%   (hashsize - 1)))]%hashsize

但是,以MSDN site1为例:

private static Hashtable employees = new Hashtable();

public static void Main()
{
    // Add some values to the Hashtable, indexed by a string key
    employees.Add("111-22-3333", "Scott");
    employees.Add("222-33-4444", "Sam");
}

假设添加第二个键会导致碰撞,因此必须使用H2。但是,当我打电话给员工[“222-33-4444”]时,哈希表如何知道使用H2?有没有单独的映射?感谢。

3 个答案:

答案 0 :(得分:3)

我认为你误解了重复。只有一个哈希函数:虚拟object.GetHashCode()(或者,如果提供IHashCodeProvider或IEqualityComparer,它使用该对象来计算哈希码)。当哈希表已满时,它会扩展其容量,并在新的更大的数组上重新分配元素。执行此操作的私有方法称为Rehash(),但它不会重新计算哈希代码。

CORRECTION

重新散列不使用新函数,而是对哈希码的前一个值进行操作;这具有搜索后续槽的效果,直到找到空的槽(用于插入/设置)或者直到检查了具有相同(初始)哈希码的所有密钥与索引密钥相等(用于检索)。

修改

直接回答您的问题:

  

假设添加第二个键会导致碰撞,因此必须使用H2。但是,当我打电话给员工[“222-33-4444”]时,哈希表如何知道使用H2?有没有单独的映射?感谢。

  1. 根据传递的密钥的哈希码计算正确的存储桶。
  2. 如果该存储桶为空,则失败。
  3. 如果存储桶的密钥与传递的密钥匹配,则返回存储桶的值。
  4. 如果哈希冲突计数为零,则失败。
  5. 从当前哈希码计算下一个哈希码。
  6. 根据新的哈希码计算正确的存储桶。
  7. 转到第2步。

答案 1 :(得分:3)

哈希表将密钥和值存储在哈希表本身中。这种方式稍后在诸如散列表查找之类的操作期间,可以保证找到的值是与用于查找的索引匹配的值。哈希表使用简单的“尝试查找成功的基本方法”方法。在这种情况下,查找方法是“使用哈希函数X”,其中X在失败时改变。

在其他方案中,查找方法是“查看表项X”(由哈希函数确定),其中X在每次失败时以包装方式增加1。

现在唠叨的问题是当值不在表中时会发生什么?好吧,这可能相当丑陋:当你在表中找到一个丢失的条目时,或者更糟糕的是,当你迭代了表中存储的条目时,你可以确定条目不是在那里 - 但在最坏的情况下可能需要“一段时间”。

请记住,由于只有一个值可以与一个键相关联,所以一旦找到了该键,就会找到该值。哈希表可以做的最糟糕的事情是必须对哈希表本身中的所有值进行相当于缓存不友好的线性搜索...但最终,它会找到值,如果它在那里因为它将存储的密钥与要求的密钥,以测试它是否在那里。唯一的优化闭合哈希表make是首先看的地方 - 在这种情况下,哈希函数1表示,然后是2,然后是3 ......

答案 2 :(得分:0)

首先尝试H1。如果找不到匹配项,则使用H2。等等。