【问题标题】:Which STL Container to use? [duplicate]使用哪个 STL 容器? [复制]
【发布时间】:2012-05-20 23:07:00
【问题描述】:

如果出现以下情况,我应该使用哪个 STL 容器:

  1. 定期插入和删除数据。
  2. 定期随机访问数据。

例如:dataset(4,10,15) 如果我想找到最接近 9 的数字,那么它应该返回 10。

  1. 我只存储一个整数。
  2. 需要排序
  3. 可以去 10 万个数据集

我想过用vector,但是vector的插入和移除很昂贵。

   vector<int>

如果我要使用列表,我必须在访问数据之前访问 O(n) 个元素。

   list<int>

我正在考虑使用 set,因为如果它被排序会很好,但我不太确定使用 SET 的效率

所以我希望有人能给出一个好的解决方案!

【问题讨论】:

  • 这完全取决于您插入和访问数据的方式,以及数据的排序方式。你需要随机访问吗?您需要保持数据的准确顺序吗?
  • 您希望如何访问您的数据?因为访问数据的向量也是 o(n) 除非您已经知道要访问的项目的索引?
  • 如果向量已排序,则查找只是 log(n),因为您可以进行二分搜索
  • 如果可以选择 Boost,请将您的结果与 Containers 库中 Boost 的“平面集”进行比较。

标签: c++ stl containers


【解决方案1】:

我认为您应该查看此 SO 帖子:In which scenario do I use a particular STL container? 小尺寸矢量将适合大多数情况,无论您打算做什么。

虽然该图表是一个指南,但定期访问容器这一事实不会影响容器的选择,除非您关心容器的大小,否则存储 int 的事实并不重要,在这种情况下,列表容器或映射中的指针对您来说很重要吗?

排序是由 map 自动完成的,但是如果容器大小足够小以适合内存,则对向量和列表进行排序会非常快。

数据插入针对容器中任何位置的列表和地图进行了优化,对于地图,您可以获得它会自行排序的好处,但如果大小足够小,那么使用新条目构建新向量可能仍然非常快。

您可能还需要考虑哈希映射,您仍然最好对您的代码进行剖析,尝试根据您的使用情况再次猜测什么是最佳的,并且您确实需要测量和剖析。

您也可以只决定 STL &lt;map&gt; 是一个足够好的余额或 &lt;set&gt; 并使用这些容器,因为它们会自动对插入和删除进行排序并且查找速度很快,但维护指针会产生开销在每个条目中,与向量相比会增加所用内存的大小,如果您不关心这一点,那么您可以考虑使用这些容器。

如果它仍然重要,那么测试和分析并比较每个容器的性能,您会惊讶于代码将如何执行您的假设。

【讨论】:

  • 图表很完美!谢谢! :D
  • 对矢量的评论+1。
  • 感谢您的详细建议!应用它! :)
  • +1 用于哈希映射,这可能是 OP 问题的最佳解决方案。
【解决方案2】:

如果要求只是性能,选择基本上应该是std::vector

它避免了基于节点的数据结构(树和列表)的许多内存分配,并利用空间局部性进行更有效的遍历。

当然,向量中间的插入/删除需要移动元素,但即使这样也很少足以使向量比其他数据结构慢。

我看到使用其他数据结构的唯一真正原因是:

  • std::map/std::set:这些非常方便。美观且易于使用,因此如果不需要最佳性能,我会在需要排序容器或键/值映射时使用它们。 (为了获得最佳性能,排序向量可能更可取)
  • 所有其他容器:可能有助于保证在面对修改时提供的正确性:向量经常重新分配和移动其内容,这会使指向向量的指针和迭代器都无效。其他数据结构在那里提供了更强的保证(对于deque,指针在末端插入/删除后保证保持有效,但迭代器仍可能无效。对于listsetmap,指针和迭代器都保证在插入/删除期间保持有效)

当然,这些只是经验法则。

在涉及性能时,唯一普遍适用的规则是“自己进行基准测试”。我可以告诉你vector 在许多常见场景中的典型表现,但我不能告诉你它在你的 代码中的表现如何,你的 编译器和你的标准库。因此,如果您担心性能,请测量它。尝试不同的替代方案,看看哪个更快。

【讨论】:

  • 您好,感谢您的回复,抱歉只是想澄清一下,所以根据我的编辑,我提供了以下示例,例如:dataset(4,10,15) 如果我想找到最接近的数字到 9,那么它应该返回 10。我的数据集可以转到 100k 数据集。那么是不是说还是用vector和sort/binarysearch比较好呢?
  • 嗯,最后一部分是重要的:测试它,如果你想确定的话。但是无论如何,二进制搜索都会破坏缓存,因此数据是否连续存储可能没什么区别。不过,对于线性遍历,向量将是一个明显的赢家。数据集的静态程度如何?是否不断修改?
  • 是的,很可能不断修改
  • 好的,这使得预测更加困难,IMO。尝试不同的策略,看看哪种方法最有效
  • 但我的直觉是向量会胜出。一个选项甚至可能是保持向量未排序,并且每次只进行一次线性扫描。更多的比较,但它更好地利用了局部性,并且节省了排序的成本——并且意味着元素在插入/删除过程中不需要移动
【解决方案3】:

一个集合足够有效地插入/删除/访问,并且它总是被排序的。唯一需要考虑的是集合中的条目是 const 的(所以顺序不会被破坏),所以要改变,你应该删除、更新和插入

【讨论】:

    【解决方案4】:

    您的问题的答案完全取决于您的数据集大小,随着列表增长到巨大的大小,执行线性遍历以获取您需要删除/插入的元素所需的时间远远超过向量执行删除/插入所需的时间。 因此,如果您的数据集很小,请使用列表,如果它很大,请使用向量。

    【讨论】:

    • 您为什么更喜欢小型数据集的列表?在那种情况下,它同样慢得离谱
    • @jalf list 速度慢得离谱。
    • @jalf 答案与 OP 试图从中选择的内容有关
    • 是的,但我不明白“如果您的数据集很小,请使用列表”。如果数据集很小,vector 与大型数据集一样快
    【解决方案5】:

    如果需要排序,使用二叉搜索树

    【讨论】:

      猜你喜欢
      • 2010-12-06
      • 2012-11-23
      • 2018-12-03
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      • 2019-10-01
      相关资源
      最近更新 更多