【问题标题】:Why unorded_set rehash complexity could be O(n^2) in worst case?为什么在最坏的情况下 unorded_set rehash 复杂度可能是 O(n^2)?
【发布时间】:2014-06-10 09:57:59
【问题描述】:

我不明白为什么它不是线性的。

关于 multiset 的类似问题有一个很好的答案: why hastable's rehash complexity may be quadratic in worst case

但是集合呢?每个键可能只有一个元素。

更新:

一个桶中有很多键也不成问题。我们可以在线性时间内完成它们。

我认为下面提到的正确答案是标准中包含 O(n^2) 重新哈希复杂性以允许开放寻址(并且可能是其他一些)实现。

【问题讨论】:

  • 重复线性加法 - 1 + 2 + ... n = n(n+1)/2
  • 即使每个key只有一个元素,也可能有多个key的hash值相同,所以答案是一样的。
  • @Mankarse:你错了,看我的回答。好吧,你是对的,有多个具有相同哈希值的键。但是,这并不意味着 O(n²) 重新散列行为。
  • 链接的问题有一个很好的答案。哪个部分让你感到困惑?哪一部分不清楚?请为您的问题添加更多详细信息。
  • @gexicide:当然可以编写这样的容器,但标准并不要求实现这样做。最差情况的 rehash 性能是 O(n²)(参见 [unord.req]/10 表 103)。

标签: c++ stl


【解决方案1】:

基本上,可以构建具有O(n) 最坏情况重新哈希时间的哈希集。甚至可以使用此属性构建一个 multiset,该属性仍然可以保证具有相同键的元素在存储桶中彼此落后,因此您声明的链接是 错误。 (嗯,不完全错,它承认可能有O(n) 实现)

它是这样工作的:

for each bucket b of old table
    for each element e in bucket b
        b' = new bucket of e
        prepend e before the first entry in b' // <---- this is the key optimization

该算法适用于集合和多集合,并且非常简单。我们不是将元素附加到新存储桶(即O(number of elements in the bucket)),而是将元素附加到存储桶O(1)(只需更改两个指针)。

当然,这会反转桶中的元素。但这没关系,因为相同元素彼此落后的关键多图假设仍然成立。

但要注意开放寻址

我的解决方案仅适用于链式散列。它不适用于开放寻址。因此,由于规范肯定希望允许这两种实现方法,它必须声明O(n²) 可能是最坏的情况,即使存在具有更好渐近运行时的实现。

【讨论】:

  • 我删除了我的答案,因为它仍然没有显示出二次方的需要。关键是,该键不需要是可排序的,但似乎该算法甚至不需要排序即可工作。我猜二次最坏的情况是为了允许以最小的内存开销实现。
  • @user2079303:是的,我现在也意识到了这一点。有了这个,我们甚至可以在不需要任何额外空间的情况下获得O(n)。请参阅我编辑的答案的最后一部分。
  • @gexicide 好的。但它只适用于链接;它不适用于开放寻址。但我恳求您:为什么我们要防范一开始就不应该发生的极端情况?
  • @Ali:对,开放式寻址不起作用。再次正确,对于set,这是一个极端情况。但这不是multiset 的极端案例。好的,OP询问了集合,但他引用了一个多集合的链接,甚至可以使用这种数据结构。但是您可能是对的,规范希望确保可能的实现也可以使用开放寻址。我会将开放地址添加到我的答案中。
  • 鉴于桶接口和插入时对稳定引用的要求,我怀疑规范是否允许开放寻址。
猜你喜欢
  • 2013-08-12
  • 1970-01-01
  • 2021-06-12
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 2012-09-12
  • 1970-01-01
相关资源
最近更新 更多