构建大型(ish)无序集合,并在开头提供所有可用数据

时间:2017-06-15 21:28:54

标签: c++ c++-standard-library unordered-set

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

的操作
unordered_set s(data); 

而不是

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

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

2 个答案:

答案 0 :(得分:4)

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

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

其次,如果你正在使用C ++ 11,你可能会在将元素插入容器时使用move-semantics受益(当然,一旦将它们放入你的容器中,你就不需要它们了。 set,对于5到2千5百万个对象应该是真的。

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

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

答案 1 :(得分:3)

  

我现在的重点是我是否可以使用像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);

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

但问题可能会有所不同。如果您查看the documentation,请说明:

  

使用范围[first,last]的内容构造容器。将max_load_factor()设置为1.0。

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

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

其中 k> 1 是一些常数。这对应于 1 / k 的负载系数。 YMMV。