在开始时使用所有可用数据构建大型(ish)无序集

Build large(ish) unordered set with all data available at the beginning

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

的事情
unordered_set s(data); 

而不是

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

STL无序集能否使用批量加载的方式加快创建速度?如果我在 table 构造之前知道预期的元素数量,我该如何调整散列 table 的参数(存储桶大小等)?

这个问题很广泛也很有趣。

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

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

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

编辑: 当然这都是关于 C++11 的,因为 unordered_set 在它之前是不可用的。我真丢人:)

My focus now is on whether I can use functions like rehash to notify the table for the upcoming size

假设你调用

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);

所以它已经根据元素的数量预先分配了大小。

不过,问题可能有所不同。如果您查看 the documentation,它表示:

constructs the container with the contents of the range [first, last). Sets max_load_factor() to 1.0.

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

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

其中 k > 1 是某个常数。这对应于 1 / k 的负载因子。 YMMV.