【问题标题】:Hash table rehashing and iterator invalidation哈希表重新散列和迭代器失效
【发布时间】:2020-11-04 17:43:08
【问题描述】:

已知哪些技术可以防止迭代器在重新散列之后/期间失效?特别是,我对具有增量重新哈希的冲突链哈希表感兴趣。

假设我们正在通过迭代器迭代哈希表,在迭代期间插入一个元素,并且该插入会导致完整或部分表重新哈希。我正在寻找允许继续迭代的哈希表变体,并确保所有元素都被访问(可能除了新插入的元素,没关系)并且没有元素被访问两次。

AFAIK C++ unordered_map 在重新散列期间使迭代器无效。此外,AFAIK Go 的地图具有增量重新散列并且不会使迭代器无效(范围循环状态),所以它可能是我正在寻找的,但我无法完全理解 source code 到目前为止。

一种可能的解决方案是有一个所有元素的双向链表,与哈希表平行,不受重新散列的影响。此解决方案需要每个元素两个额外的指针。我觉得应该存在更好的解决方案。

【问题讨论】:

    标签: algorithm go data-structures hashmap hashtable


    【解决方案1】:

    AFAIK C++ unordered_map 在重新散列期间使迭代器无效。

    正确。 cppreference.com 总结了unordered_map 迭代器失效:

    Operations                                     Invalidated
    ==========                                     ===========
    All read only operations, swap, std::swap      Never
    clear, rehash, reserve, operator=              Always
    insert, emplace, emplace_hint, operator[]      Only if causes rehash
    erase                                          Only to the element erased 
    

    如果您想使用unordered_map,您的选择是:

    • 在开始迭代/插入之前调用reserve(),以避免重新散列
    • 在开始迭代/插入之前更改 max_load_factor(),以避免重新散列
    • 在迭代期间将要插入的元素存储在 vector 中,然后将它们移动到 unordered_map
    • 创建例如vector<T*>vector<reference_wrapper<T>> 到元素,迭代它而不是 unordered_map,但仍然插入到 unordered_map

    如果你真的想要增量重新散列,你可以编写一个包含两个 unordered_maps 的类,当你看到一个会导致第一个映射重新散列的插入时,你开始插入第二个(为此你' d 保留第一张地图大小的两倍)。您可以手动控制第一个地图中的所有元素何时转移到第二个地图,或者让它作为其他操作的副作用发生(例如,每次插入新元素时迁移一个元素)。这种包装方法比从头开始编写增量重新散列表要容易得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 2016-01-23
      • 2012-12-27
      • 2016-01-29
      • 2012-02-28
      • 1970-01-01
      相关资源
      最近更新 更多