C++ 我应该在插入STL集合之前随机洗牌吗?

C++ 我应该在插入STL集合之前随机洗牌吗?,c++,stl,set,C++,Stl,Set,我需要插入1000万个字符串到C++ STL集中。字符串已排序。如果我按排序顺序插入字符串,是否会出现病态问题?我应该先随机化吗?或者G++STL实现会自动为我重新平衡吗?set实现通常使用红黑树,这将为您重新平衡。但是,如果在插入之前随机化数据,则插入可能会更快(也可能不会更快)——唯一可以确保的方法是使用集合实现和特定数据进行测试。无论哪种方式,检索时间都是一样的。 set:“使用自平衡二进制搜索树实现。”也许“无序集”可以作为替代方案。实现将自动重新平衡。但是,如果您知道输入是经过排序的,

我需要插入1000万个字符串到C++ STL集中。字符串已排序。如果我按排序顺序插入字符串,是否会出现病态问题?我应该先随机化吗?或者G++STL实现会自动为我重新平衡吗?

set实现通常使用红黑树,这将为您重新平衡。但是,如果在插入之前随机化数据,则插入可能会更快(也可能不会更快)——唯一可以确保的方法是使用集合实现和特定数据进行测试。无论哪种方式,检索时间都是一样的。


set:“使用自平衡二进制搜索树实现。”

也许“无序集”可以作为替代方案。

实现将自动重新平衡。但是,如果您知道输入是经过排序的,那么您可以给它一些帮助:您可以在执行插入时提供“提示”,在这种情况下,为先前插入的项提供迭代器正是为下一次插入提供的正确提示。在这种情况下,每个插入将具有摊销常量复杂性,而不是您预期的对数复杂性。

g++的libstdc++将红黑树用于集合和映射

这是一个自平衡树,插入总是O(logn)。C++标准还要求所有实现都具有这种特性,所以在实践中,它们几乎总是红黑树,或者非常相似。
所以不要担心元素的放置顺序。

我唯一的问题是:您真的需要
集合吗

如果数据已经排序,并且在创建后不需要插入/删除元素,则使用
deque
会更好:

  • 使用用于检索的
  • 您将获得更少的内存开销。。。和更好的缓存位置

关于
binary\u search
:我想你需要的不仅仅是一个
ForwardIterator
来进行二进制搜索,我猜这个网站又关闭了:(

一个非常便宜和简单的解决方案是从字符串集合的两端插入。也就是说,首先添加“a”,然后添加“ZZZZZ”,然后添加“AA”,然后添加“ZZZZY”直到你在中间遇到为止。它不需要花费大量的洗牌,但它可能会避开病理情况。

我对STL集的一个抱怨是,你不能提前分配内存。如果把1000万个字符串放入STL集,这将是我关心的问题。插入操作的复杂性。为什么要随机化?@Kyril它保证了最大随机化顺序可能会提供更好的性能,因为可能需要进行较少的再平衡。@Lib我肯定在一个集合中插入了大约一百万个字符串,没有问题。@liberkid:您不能指定一个自定义分配器作为第三个模板参数吗Meter到
std::set
,例如使用
boost::pool
?这将允许您使用类似于基于池的分配器的东西。很好的建议,但树会经常重新平衡。@Matthieu:True。我很确定,至少在复杂性方面,它比先洗牌数据要好。对于洗牌数据,总体复杂性s O(N lg N)因为您必须为每个新元素搜索插入点。对数据进行排序后,每个插入都有摊销常数复杂性,因此总体复杂性摊销O(N)。但在实际操作中是否更好仍有疑问。如果您可以将所有数据保存在内存中,则可以尝试从一开始就完美地构建树(递归地将数据平分).我喜欢这种二分法,尽管我认为在实践中,考虑到记录的数量,由于缓存问题,它会比重新平衡慢,因为我们会不断地访问新的内存页。不,文档是正确的。二进制搜索使用“advance”这对于随机访问迭代器是常数时间,对于ForwardIterator是线性的。因此ForwardIterator是算法的最低要求。请参阅上的脚注。坦白说,我宁愿使用集合,因为这是我需要的功能。@BennyG:谢谢。正如两个站点上对于非随机访问迭代器所指出的,步骤数是线性的,不是吗t对数。我曾以某种方式假设我们只能有对数复杂度。@vy32:因为你担心性能,我以为你已经准备好弄脏你的手了。如果你只是想继续使用
集,请测量时间,如果它足够好,你就不必担心它。结果证明你是对的!我能够做到提前创建列表,只使用二进制迭代器。我将在程序中预先编译的列表存储为一个200000个元素的大数组。(我最终编写了自己的二进制搜索,而不是使用C++向量。)