【问题标题】:How does std::unordered_set allocate bucket to provide O(1) lookup?std::unordered_set 如何分配桶以提供 O(1) 查找?
【发布时间】:2021-01-08 10:07:19
【问题描述】:

如果散列函数良好,unordered_set 应该提供 O(1) 的查找时间。
每个桶包含具有相同哈希值的项目。
让我们假设我们的散列函数是理想的并且完全没有冲突。
哈希值可以从 0 到 max(std::size_t) 变化。
如何在不为存储桶分配连续内存间隔的情况下组织 unordered_set 并提供 O(1) 查找?
我们不能分配连续的内存间隔,因为如果我们分配,那么我们将大量内存仅用于几个哈希值 - 例如 0 和 1000000。
中间的值根本没有使用,但我们为它们分配了内存。

【问题讨论】:

  • looking up a key 的复杂性是“[c] 平均而言是恒定的,最坏的情况是与容器大小呈线性关系。”,而不是 O(1)。
  • Each bucket contains items with the same hash value. Let's assume that our hash function is ideal and gives no collisions at all. 这两个语句的含义相反。如果您的哈希是理想的,那么您将拥有与元素一样多的桶。所以你的查找将是 O(1)。
  • 是的,会的。但是如何分配这些桶呢?如果我们连续分配它们,那么我们会使用大量内存但提供快速查找。
  • 你想多了。 unordered_set 的实现方式是桶数不超过项目数。 IMO 这个问题来自XY problem
  • 哈希值通常不是桶索引。参见例如Wikipedia on hash tables

标签: c++ performance collections unordered-map unordered-set


【解决方案1】:

每个桶都包含具有相同哈希值的项目。

错了。每个桶“包含”具有相同值的项目:

       hash(key) % 当前桶数

让我们假设我们的哈希函数是理想的并且完全没有冲突。

在修改前的空间中没有冲突不一定是理想的:重要的是修改后的冲突(或者如果有 2 的幂的桶计数,例如 Visual C++,则屏蔽)到桶的数量。

哈希值可以在 0 到 max(std::size_t) 之间变化。 如何在不为桶分配连续内存间隔的情况下组织 unordered_set 并提供 O(1) 查找?

当表具有最大的size() 时,每个值/元素通常有 1 到 ~2 个存储桶。您可以通过调用max_load_factor(float) 来确定表格何时调整大小来对其进行一些自定义,但您无法自定义调整大小的程度——这由实现决定。 GCC 通常会选择一个比当前大小大一倍的素数。 Visual C++ 通常会将桶加倍。

我们不能分配连续的内存间隔,因为如果我们分配,那么我们会使用大量内存来分配几个哈希值——例如 0 和 1000000。 中间的值根本没有使用,但我们为它们分配了内存。

这忽略了将哈希值修改到桶计数中。 (它也忽略了稀疏数组的可行性,这可能是实用的,因为虚拟地址空间可能比支持它的物理 RAM 大得多,但这不是哈希表的重点。)

【讨论】:

  • (我建议你对哈希表做一些背景阅读——也许this answer 会是一个好的开始)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-29
  • 2012-02-23
  • 2018-07-26
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多