构建大型无序集,并在开始时使用所有可用数据



我遇到需要优化无序集合创建的情况。预计元素数量约为5-25M。我的第一个想法是,我应该事先准备所有数据并做类似的事情

unordered_set s(data); 

而不是

for (auto& elem : data)
s.insert(elem); 

STL 无序集可以使用批量加载方法并加快其创建速度吗?如果我在表构造之前知道预期的元素数,如何调整哈希表的参数(存储桶大小等)?

这个问题非常广泛和有趣。

首先,有一种称为 reserve 的特殊方法 - 它允许您在实际插入元素之前为许多元素预先分配存储。预先分配足够的内存(并避免在插入过程中重新定位)是一种非常强大的方法,通常用于大型数据集。请注意,它也适用于各种标准容器,包括vectorunordered_map等。

其次,如果您使用的是 C++11,则在将元素插入容器时使用 move-语义可能会受益(当然,假设一旦它们被放置在集合中,您就不需要它们在您的 feed 中,这对于 5 到 25 百万个对象应该是正确的)。

这两种技术是一个良好的开端。您可能需要通过设置不同的哈希函数,甚至选择不同的unordered_set实现来进一步调整它。但在这一点上,你应该提供更多信息:你的价值对象是什么,它们的生命周期是什么;您认为您的应用程序中可接受的插入时间是多少。

编辑:当然,这一切都是关于C++11的,因为在此之前unordered_set不可用。我感到羞耻:)

我现在的重点是我是否可以使用 rehash 等函数来通知表即将到来的大小

假设你打电话

unordered_set s(begin(data), end(data)); 

虽然该标准没有规定实现,但一个好的实现将能够识别元素的数量,并相应地预分配大小。例如,如果您查看 gcc 使用的源代码(由我/usr/include/c++/5/tr1/hashtable.h),它使用

_M_bucket_count = std::max(_M_rehash_policy._M_next_bkt(__bucket_hint),
_M_rehash_policy.
_M_bkt_for_elements(__detail::
__distance_fw(__f,
__l)));
_M_buckets = _M_allocate_buckets(_M_bucket_count);

因此,它已经根据元素的数量预先分配了大小。

不过,问题可能有所不同。如果您查看文档,它会指出:

使用范围 [第一个,最后一个] 的内容构造容器。将 max_load_factor() 设置为 1.0。

这样可以节省空间,但可能会导致冲突。为了减少碰撞,您可以使用

unordered_set s(begin(data), end(data), k * data.size()); 

其中k> 1是某个常数。这对应于1/k的负载系数。扬子晚报.

最新更新