我有一种情况需要优化无序集的创建。预期的元素数量约为5-25M。我的第一个想法是,我应事先准备好所有数据并执行类似
的操作unordered_set s(data);
而不是
for (auto& elem : data)
s.insert(elem);
STL无序集可以使用批量加载方法并加快其创建速度吗?如果我在表格构造之前知道预期的元素数量,我该如何调整哈希表的参数(桶大小等)?
答案 0 :(得分:4)
这个问题非常广泛和有趣。
首先,有一个名为reserve的特殊方法 - 它允许您在实际插入之前为多个元素预先分配存储空间。预先分配足够的内存(并避免在内容期间重新定位)是一种非常强大的方法,通常用于大型数据集。请注意,它也适用于各种标准容器,包括vector
,unordered_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。