我自己从未使用std::list<T>
。当我们已经拥有std::vector<T>
时,我想知道人们何时使用它,就像具有连续内存的数组一样。当我们需要顺序容器时,std::vector
似乎是一个完美的选择!
所以我的问题是
std::list
超过std::vector
的时间?为什么呢? std::vector
而不是std::list
?为什么?如果有性能考虑,请列出详细说明/信息。
如果可能,请引用一些参考文献,以支持您的回答。
答案 0 :(得分:29)
所以我的问题是:你更喜欢
std::list
而不是std::vector
?
当我在性能敏感区域中需要顺序容器时, 分析 显示std::list
更快。
到目前为止,这从未发生在我身上。
(当我不得不在中间存放大量插入/移除物体时,我可能会首先尝试std::list
。但是,在实践中,我从未遇到过这样的用途 - 案例。)
答案 1 :(得分:15)
列表更适合插入或删除中间的任何位置,向量最好插入到最后。
矢量也更适合访问元素。
这是他们实施方式的人工制品。
因此,如果集合变化很小(与访问相比)或者更改集中在最后,我会使用向量。
如果变化的数量很大(与访问相比)并且它们不在最后,我会使用一个列表。
举例来说,在程序启动时读取集合并且几乎不会更改它(或者如果更改是添加到结尾),这将是向量的良好候选。
另一方面,对于一个特别受欢迎且善变的摇滚明星的电话簿应用程序,我正在寻找列表。实际上我会关注数据库连接,但这是我能在短时间内提出的最好的例子: - )
至于引用,最新的C ++ 0x草案在部分(23.3.4,列表)中说明:
列表是一个序列容器,它支持双向迭代器,并允许在序列中的任何位置进行常量时间插入和擦除操作,并自动处理存储管理。与矢量和deques不同,不支持对列表元素的快速随机访问。
第23.3.5节(关于载体):
vector是一个支持随机访问迭代器的序列容器。此外,它支持(摊销)最后的恒定时间插入和擦除操作;在中间插入和擦除需要线性时间。
答案 2 :(得分:11)
在std :: list和std :: vector之间进行选择时,需要考虑一些权衡因素。另外std :: list不是关于连续内存的,如果你无法承受迭代器失效或者你需要在begin / middle / end中进行分摊的常量时间插入,它会非常有用。
答案 3 :(得分:7)
我首选std::list
的唯一(几次)是由于list::splice
成员函数。如果您在列表中或列表之间的子范围内进行混洗,则此操作可能比使用std::vector
快得多。
答案 4 :(得分:4)
我不需要重复基础知识,但我学到的很难的方法是,如果插入性能相关并且你有“大”对象,那么你应该真的考虑std: :list,甚至如果你只是在最后插入。 (好吧,列表或可能是智能指针/ ptr_vector的向量。)
我们有一些使用案例,我们必须建立一个先验未知大小的多个小std :: string结构的集合,并使用std :: vector完全杀死插入性能和添加了一个不可忽视的内存开销。
未知计数插入场景中std :: vector的问题是:
这不是为了bash std :: vector,我仍然默认使用它 - 但知道你的数据结构会有什么期待!
答案 5 :(得分:2)
除了其他答案,
基于节点的容器(list
/关联容器)可以提供强大的功能
例外保证。
即使容器变异操作(例如插入)抛出一个
异常,保留元素的所有指针/引用/迭代器
有效的。
但是,线性存储器(分段连续存储器单元)容器可以
只提供基本保证。
当插入抛出时,即使插入没有实际执行,
指针/引用/迭代器可能无效
(虽然容器本身可以安全地被破坏)。
答案 6 :(得分:1)
当您需要经常修改除前面或后面以外的其他位置的序列时,可以使用std :: list。在std :: std :: list中的std :: vector中,此类操作的开销很大。
答案 7 :(得分:1)
当其无效语义和性能特征符合您的要求时使用列表。
List可以在O(1)中的任何地方插入/擦除/拼接,这不会使任何迭代器无效。除了最后,向量是用于插入/擦除的O(n),并且如果大小&lt;容量;矢量不能拼接。例如,在另一个答案中提到了缓存局部性,性能甚至比这更微妙。
答案 8 :(得分:1)
std::list
几乎完全是我唯一的vector
不共享的属性,而且知道我对list
的指针始终有效。因此,我可以使用它来包含我在单个区域中需要的任何资产的所有实例,同时还借用对其他对象的引用。我能想到的最好的例子是图像加载器,它只在内存中保留一个像素副本,同时将指针指向多个实体,以便它们都可以从中抽取。
所有vector
都是O(1)访问时间。虽然这听起来像是一笔巨大的资产,但实际上我很少需要在从“第一个”到“最后一个”的步骤之外访问数据结构中的项目
答案 9 :(得分:1)
有些人会说,你应该never ever ever use linked list in your code again。 ;)
一个问题是,向量具有更好的引用位置,并且由此产生的大的性能提升在许多情况下将超过更多(算法)高效操作的优势,例如删除并插入链表。
(请参阅上面的博客文章,了解有关此特定问题的更多讨论,以及基准测试等。)
因此,std :: vector通常会胜过std :: list,即使你正在进行一定数量的操作,列表会更自然(例如,任意元素删除,插入任意位置或拼接)
但请注意,即使你做做了很多这类操作,你最好还是在std :: vector的连续缓冲区中“托管”你的列表。
我在本博文中更详细地讨论了这个问题,并附有一些图表和代码示例:http://upcoder.com/12/vector-hosted-lists/
在特定情况下,当您需要删除任意元素,但不需要插入任意位置或拼接时,完整链接列表的一个很好的替代方法可以是将条目标记为“死”并跳过迭代期间这些死的条目。
答案 10 :(得分:0)
当你进行大量删除/插入时,你应该使用一个列表。
如果元素的总大小不会发生很大变化,并且您进行了一些交换,则可以使用向量。