unordered map -在c++ std::unordered_map中预分配桶

unordered map - Pre-allocating buckets in a C++ std::unordered_map

本文关键字:unordered map 预分配 std c++      更新时间:2023-10-16

我使用gnu++0x的std::unordered_map来存储大量数据。我想为大量元素预先分配空间,因为我可以限制使用的总空间。

我想要做的是调用:

std::unordered_map m;
m.resize(pow(2,x));

,其中x是已知的。

std::unordered_map不支持此操作。如果可能的话,我宁愿使用std::unordered_map,因为它最终将成为标准的一部分。

其他约束:

需要可靠的O(1)访问和映射的突变。所需的散列和比较函数已经是非标准的,并且有些昂贵。O(log n)突变(如std::map)代价太大。

->昂贵的哈希和比较也使得基于摊销的增长过于昂贵。每次额外的插入都需要对这些函数进行O(n)次操作,这将导致算法运行时间中额外的二次项,因为指数级存储需求需要O(n)次增长。

m.rehash(pow(2,x));

如果pow(2, x)是您想要预分配的桶的数量。您还可以:

m.reserve(pow(2,x));

,但现在pow(2, x)是您计划插入的元素的数量。这两个函数除了预分配桶之外什么都不做。它们不插入任何元素。而且它们都是为了你的用例而使用的。

注意:你不能保证得到完全的pow(2, x)桶。一些实现将只使用桶的数量,这是2的幂。其他实现将只使用素数的桶。还有一些将只使用质数的一个子集来表示桶的数量。但在任何情况下,实现都应该接受您的提示您想要的桶数,然后在内部四舍五入到下一个可接受的桶数。

下面是最新的(N4660)用来指定rehash参数的精确措辞:

a.rehash(n):后置条件: a.bucket_count() >= a.size() / a.max_load_factor() and a.bucket_count() >= n .

此后置条件确保bucket()_count() >= nload_factor()小于或等于max_load_factor()

随后根据rehash(n)定义reserve(n):

a.reserve(n):与a.rehash(ceil(n / a.max_load_factor()))相同

我认为对于无序映射来说,预先分配内存并不重要。STL预计为O(n)平摊插入时间。在我看来,在您知道这是代码的瓶颈之前,您可以省去编写自己的分配器的麻烦。

我建议您为std::unordered_map编写您自己的分配器,以您想要的方式精确地分配内存。

构造函数接受一个参数"size_type bucket_count"根据http://en.cppreference.com/w/cpp/container/unordered_map/unordered_map

所以最简单的方法来做你的例子代码所说的是:
std::unordered_map m{ pow(2,x) };

这将更有效,因为它没有定义在构造时保留多少桶,否则,它可能必须分配,然后在之后调用reserve时释放。

我认为rehashreserve只有在您事先知道映射值将占用多少内存时才有效。如果映射值很复杂或大小动态变化(例如矢量),则需要自己实现。例如,如果内存大小允许,可以保留可能存在的最大的容器。