STL向量的性能(内存和速度)+排序+相等与unordered_set相比使用纯集

时间:2015-03-22 13:23:51

标签: performance algorithm c++11 stl unordered-set

我有以下情况:

  1. 我有一堆不需要连续顺序的元素。
  2. 我可以在初始化期间第一次插入元素
  3. 我需要执行containerA == containerB操作。
  4. 元素N的数量最多可以是100,但是要通过平均值。案例分析的目的,我会说N可以是100,10k或100k
  5. 鉴于,我的要求std :: set不是一个好选择。我可以使用push_back N*O(1)和std :: sort O(NlogN)在向量中进行所有元素插入,并进行相等比较(N);总计2N+NlogN可以轻松击败std :: set memory / speed。

    此主题已在此处进行了详细审核: http://lafstern.org/matt/col1.pdf 和这里: What is the difference between std::set and std::vector?

    让我们继续讨论如果我使用新的unordered_set。 N*O(1))元素的插入(N +相等查找(N平均案例)总计为2N

    现在,对于unordered_set,我需要创建一个哈希,这对我的情况来说并不容易。我猜测只有哈希部分会导致我的复杂数据结构超过2N

    但是,为什么对于简单的unique_ptr值插入,有人会得到以下性能结果: http://kohei.us/2010/03/31/stl-container-performance-on-data-insertion/

    似乎矢量排序+相等仍然比unordered_set更好,直到大量元素(100k)。 unordered_set不使用红黑树吗?那么这个性能影响来自哪里?

    这里有一个稍微相关的帖子: Performance of vector sort/unique/erase vs. copy to unordered_set

1 个答案:

答案 0 :(得分:3)

如果你的元素有一个简单的排序函数,并且你知道它们是不同的,那么你最好将它们放在一个向量中并对它们进行排序。理论上,具有良好散列函数的基于散列表的解决方案可以进行比较O(n)而不是O(n log n),但是有许多减轻事实:

  • 日志 n 是一个小数字。例如,如果n是二十亿,那么 log n 是31(使用二进制日志,这通常是隐含的)。

  • 标准库无序集合需要为每个元素分配。这是规范有效要求的,因为向无序集合添加元素不会使对现有元素的引用无效,与标准库向量的情况不同。

  • 每个桶完成对无序集合的迭代(同样,这在规范中),结果是迭代涉及随机存储器访问。迭代向量是顺序的,这对缓存更友好。

简而言之,即使排序为O(n log n),基于O(n)散列的解决方案很可能具有较大的每元素常量,并且由于log n是一个较小的数字,基于矢量的解决方案将更快。通常要快得多。

基于散列的解决方案的速度会慢多少取决于分配器的速度,并且不同的标准库实现之间存在相当大的差异。但即使是超快速的分配器也不太可能为您提供有竞争力的性能,并且当您的表变得足够大时,哈希表的缓存不友好性将变得非常重要。

即使你有一些重复的元素,你可能会更好地使用向量,但这取决于你有多少重复。由于哈希表可能占用的内存至少是具有相同元素数量的向量的两倍,因此只要你不希望元素的数量是多少,一个简单的经验法则就是使用向量。超过两倍的独特元素。 (排序后很容易消除重复。有一个标准的库函数可以做到这一点。)