【问题标题】:How do I prevent rehashing of an std::unordered_map while removing elements?如何在删除元素时防止重新散列 std::unordered_map?
【发布时间】:2012-11-23 16:56:45
【问题描述】:

我有一个 std::unordered_map,我将从迭代中删除元素。

auto itr = myMap.begin();
while (itr != myMap.end()) {
    if (/* removal condition */) {
        itr = myMap.erase(itr);
    } else {
        ++itr;
    }
}

我想阻止地图执行任何昂贵的操作,直到我完成删除所有需要删除的元素。我有正当的担忧吗?我是否误解了内部存储的工作原理?

【问题讨论】:

    标签: c++ map iterator hashtable unordered-map


    【解决方案1】:

    erase 期间禁止无序容器重新散列:

    [unord.req]/p14:

    erase 成员只能使迭代器和对 被擦除的元素,并保持元素的相对顺序 没有被删除。

    [unord.req]/p9:

    重新散列使迭代器无效,更改元素之间的顺序,以及...

    你的代码没有问题。

    【讨论】:

    • 我知道 4 年后我们正在研究这个问题,但我很高兴看到这个答案加入其中。再次查看文档,很明显最糟糕的复杂性不是来自潜在的重新散列,而是来自散列冲突。我认为这是正式的正确答案。
    • 所以表只能增长。?
    • erase 下,无序容器中的桶数永远不会减少。在rehash下允许数字缩小,所有实现都会这样做。
    【解决方案2】:

    我不确定它是否有效,我在文档中没有找到确认 - 但如果 unordered_map 根据经典哈希表数据结构重新散列,您可以 set the max_load_factor到一个非常高的值并在完成后将其重置为正常值(这将触发重新哈希)(或者如果您可以预测将删除多少元素,则将其重置为预测值)。

    就经典哈希表而言,它应该可以工作,因为当大小小于1/max_load_factor 时会发生减小表时的重新哈希。

    (不确定在 C++ 中是否如此,但我认为值得一试,因为它真的很容易实现)。

    【讨论】:

      【解决方案3】:

      据我所知,std::unordered_map 可以在erase(itr) 上重新散列:

      C++11 表 103 -- 无序关联容器要求

      a.erase(q)

      删除指向的元素 通过q。返回值为 紧跟在q 之后的迭代器 在擦除之前。

      平均情况 O(1), 最差 案子 O(a.size())

      因此,您似乎确实有一个合理的担忧。至于解决它,我可以提出几个途径:

      1. 确保这是一个实际问题而不是假设问题。分析应用程序,查看 C++ 库的源代码等。
      2. 如果是实际问题,请考虑使用不同的容器或不同的算法。
      3. 考虑通过与每个元素关联的布尔标志简单地标记要删除的元素,并不时清除已删除的元素,从而摊销成本。
      4. 考虑按照 cmets 中 @amit 的建议对负载系数进行试验。尽管仍允许容器花费 O(a.size()) 时间来擦除元素,但不同的负载因子可能会影响应用程序的实际性能。

      【讨论】:

      • 虽然信息丰富且相关 - 它没有回答问题:How do I prevent rehashing of an std::unordered_map while removing elements?
      • @amit:如果您在字里行间阅读,确实如此(确切问题的答案是您不能:))
      • @amit:嗯,最坏的情况是O(a.size())。它不依赖于其他任何东西,包括负载因子。
      • @NPE:最坏的情况是基于非常糟糕的哈希值,而不是重新哈希。所有 unordered_* 操作都有可能此时容器中的所有对象碰巧具有相同的哈希值。我几乎可以肯定 .erase 目前被禁止重新散列。
      • 这个答案不正确。我已经添加了一个正确的答案。
      猜你喜欢
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多