预测std :: unordered_set或std :: unordered_map的大小调整/重新哈希

时间:2019-02-22 19:49:56

标签: c++

是否可以可靠地预测对std :: unordered_set或std :: unordered_map的插入何时会调整基础存储的大小并重新散列项目?

我的程序维护着一个无序的项目集,该项目会不断增长,但是有些项目可能会“过期”,因此我可以从集合中删除这些项目以节省空间。一个好时机是在插入项目之前,以防插入会导致集合调整大小并重新哈希。无论如何,该集合都需要扫描其所有元素,甚至可能阻止其调整大小。)

但是到目前为止,我还没有找到一种预测可在标准库的实现中使用的调整大小的方法。下面的代码暴露了Microsoft的实现与libstdc ++之间的差异。

std::unordered_set<int> set;
for (int i=0; i < 1000; ++i) {
    size_t bucketsBefore = set.bucket_count();
    set.emplace(i);
    size_t bucketsAfter = set.bucket_count();
    bool resized = bucketsAfter > bucketsBefore;
    if (resized)
        printf("Size from %zu to %zu, buckets from %zu to %zu.\n", set.size() - 1, set.size(), bucketsBefore, bucketsAfter);
}

在Windows中使用MSVC编译时,会打印

Size from 8 to 9, buckets from 8 to 64.
Size from 64 to 65, buckets from 64 to 512.
Size from 512 to 513, buckets from 512 to 1024.

在Linux中使用g ++编译时,会打印出

Size from 0 to 1, buckets from 1 to 3.
Size from 2 to 3, buckets from 3 to 7.
Size from 6 to 7, buckets from 7 to 17.
Size from 16 to 17, buckets from 17 to 37.
Size from 36 to 37, buckets from 37 to 79.
Size from 78 to 79, buckets from 79 to 167.
Size from 166 to 167, buckets from 167 to 337.
Size from 336 to 337, buckets from 337 to 709.
Size from 708 to 709, buckets from 709 to 1493.

就负载系数而言,这意味着当负载系数超过1时,Microsoft实现将调整集合的大小,但在负载系数达到1时则为libstdc ++。

现在,我想知道有什么好的方法。有选项。

  1. 调整大小后删除过期的项目。更强大的选项,但是通过这种方式,您将永远无法避免调整大小。那就是我现在要做的。
  2. 当libstdc ++执行调整大小时,删除过期的项目。这个想法还不错,但是如果存在第三个实现可以更早调整大小的实现(例如,当负载系数达到1-epsilon时),那么对于该实现,我将永远不会删除过期项。鉴于Microsoft和libstdc ++已经对负载因子进行了不同的处理,我看不出为什么不会出现这种第三种实现的原因。还是有原因?

1 个答案:

答案 0 :(得分:1)

您可以考虑使用boost::intrusive::unordered_set,并根据负载系数和expired项的数量来重新整理自己。