【问题标题】:How hashtable track the existing key index when it resize?哈希表在调整大小时如何跟踪现有的键索引?
【发布时间】:2012-11-27 10:50:41
【问题描述】:

我想知道哈希表在增加容量时如何找到正确的索引。例如,假设我有一个默认容量为 10 的哈希表。现在我们必须添加 (key,value) 对 [14,"你好 1"]

使用下面的索引机制,我们将为上面的键 '14' 获得的索引是 '4'。所以 hashtable 会把这个 (key,value) 对保存在索引 4 中。

int index = key.GetHashCode() % 10

现在我们继续将项目添加到哈希表中,它达到了负载因子。所以是时候调整大小了。让我们假设 hastable resize 到 20。

现在我要在这个哈希表中搜索我的旧键“14”。现在根据索引机制,我会得到这个键的索引为 14。所以我将从索引 14 开始搜索哈希表,但理想情况下它在索引 4 中。

所以我的问题是哈希表在调整大小时如何跟踪现有的键索引?或者哈希表在调整大小时是否会重新散列所有现有键?

【问题讨论】:

  • @MitchWheat - 他的标签有点......含糊不清,所以我没有声明 c# 实现的作用。我将删除那个并重申:“嗯,这取决于它是如何实现的”。
  • 在这篇文章中有一节“加载因素和扩展哈希表”,读完后看起来C#哈希表也调整大小msdn.microsoft.com/en-us/library/…
  • 我删除了 Java 标记,很抱歉造成混乱
  • 您是在询问 .Net 实现,还是扩展哈希表的一般策略?
  • @Josh:它用于 .Net 实现。

标签: c# data-structures hash hashtable


【解决方案1】:

您可能想阅读hash tables,但我认为您缺少的概念是:

  • 对于给定的键,比如“asdf”,有一个给定的 32 位 int 哈希码。
  • 要获取索引存储中的位置,您应用一个模数 (%) 为 hashCode % length - 因此,如果您将表从 10 增加到 20,结果将更改为新索引。实现当然会确保每个现有条目都在新表的正确存储桶中。

【讨论】:

    【解决方案2】:

    我查看了Shared Source CLI implementation for .Net,看起来条目在扩展时重新散列。但是,没有必要使用 .GetHashCode() 重新计算 HashCode。

    如果您查看实现,您会看到 expand() 方法,其中发生以下步骤:

    1. 会创建一个临时存储桶数组,并将其调整为大于其当前大小两倍的最小素数。
    2. 新数组是通过从旧存储桶数组重新散列来填充的。

    .

    for (nb = 0; nb < oldhashsize; nb++)
    {
        bucket oldb = buckets[nb];
        if ((oldb.key != null) && (oldb.key != buckets))
        {
            putEntry(newBuckets, oldb.key, oldb.val, oldb.hash_coll & 0x7FFFFFFF);
        }
    }
    
    
    
    private void putEntry (bucket[] newBuckets, Object key, Object nvalue, int hashcode)
    {
        BCLDebug.Assert(hashcode >= 0, "hashcode >= 0");  // make sure collision bit (sign bit) wasn't set.
    
        uint seed = (uint) hashcode;
        uint incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)newBuckets.Length - 1)));
    
        do 
        {
            int bucketNumber = (int) (seed % (uint)newBuckets.Length);
    
            if ((newBuckets[bucketNumber].key == null) || (newBuckets[bucketNumber].key == buckets)) 
            {
                newBuckets[bucketNumber].val = nvalue;
                newBuckets[bucketNumber].key = key;
                newBuckets[bucketNumber].hash_coll |= hashcode;
                return;
            }
            newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000);
            seed += incr;
            } while (true);
        }
    }
    

    新数组已经构建完成,后续操作中会用到。

    另外,来自 MSDN 关于 Hashtable.Add():

    If Count is less than the capacity of the Hashtable, this method is an O(1) operation. If the capacity needs to be increased to accommodate the new element, this method becomes an O(n) operation, where n is Count.

    【讨论】:

      猜你喜欢
      • 2011-06-24
      • 1970-01-01
      • 2018-03-05
      • 2013-12-21
      • 2012-10-14
      • 2021-03-14
      • 2017-06-07
      • 2014-04-21
      相关资源
      最近更新 更多