对于不需要随机访问列表元素的简单链接列表,使用std::list
而不是std::vector
是否有任何明显的优势(性能或其他方面)?如果需要向后遍历,那么在迭代其元素之前使用std::slist
和reverse()
列表会更有效吗?
答案 0 :(得分:56)
通常情况下,性能问题的最佳答案是profile针对您的用例的两种实现,并查看哪种更快。
一般情况下,如果您在数据结构中插入(除了最后),那么vector
可能会更慢,否则在大多数情况下vector
的效果要好于list
如果仅用于data locality issues,这意味着如果数据集中相邻的两个元素在内存中相邻,那么下一个元素将已经位于处理器的缓存中,并且不必将内存页面错误归入高速缓存中。
还要记住,vector
的空间开销是常量(3个指针),而list
的空间开销是为每个元素支付的,这也减少了完整元素的数量(数据加上开销),任何时候都可以驻留在缓存中。
答案 1 :(得分:26)
在C ++中想到的默认数据结构是 Vector 。
考虑以下几点......
1]遍历:
列表节点分散在内存中,因此列表遍历会导致 缓存未命中 。但是向量的遍历是平滑的。
2]插入和删除:
当您对Vector执行此操作时,必须移动平均50%的元素,但缓存非常擅长!但是,对于列表,您需要 遍历到插入/删除点...... 所以再次......缓存未命中!
令人惊讶的是,矢量也赢得了这个案例!
3]存储:
使用列表时,每个元素有2个指针(前向和后向),因此List比Vector大得多!
向量只需要比实际元素需要更多的内存。
Yout应该有理由不使用矢量。
答案 2 :(得分:12)
根本没有。列表优于Vector,但顺序访问不是其中之一 - 如果这就是你所做的一切,那么矢量就更好了。
然而..添加额外元素比列表更昂贵,特别是如果你插入中间。
了解这些集合是如何实现的:向量是一个连续的数据数组,列表是一个包含数据和指向下一个元素的指针的元素。一旦你理解了这一点,你就会明白为什么列表对插入有好处,对随机访问有害。
(因此,向量的反向迭代与正向迭代完全相同 - 迭代器每次只减去数据项的大小,列表仍然必须通过指针跳转到下一个项目)
答案 3 :(得分:4)
如果您需要向后遍历,则滑板不太可能是您的数据结构。
传统(双重)链接列表为您提供列表中任何位置的恒定插入和删除时间;向量仅在列表末尾给出分摊的常量时间插入和删除。对于向量插入和删除时间,除了结束之外的任何地方都是线性的。这不是全部故事;也有不变因素。向量是一种更简单的数据结构,根据上下文有优点和缺点。
了解这一点的最佳方法是了解它们的实施方式。链表具有每个元素的下一个和前一个指针。向量具有索引所寻址的元素数组。从中可以看出,两者都可以进行有效的前向和后向遍历,而只有一个向量可以提供有效的随机访问。您还可以看到链表的内存开销是每个元素,而向量是常量。您还可以看到为什么两个结构之间的插入时间不同。
答案 4 :(得分:4)
有关该主题的一些严格基准: http://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html
正如其他人所指出的,连续的内存存储意味着std :: vector对于大多数事情来说更好。几乎没有充分的理由使用std :: list,除了少量数据(它可以全部适合缓存)和/或频繁擦除和重新插入的地方。 复杂性保证与实际性能无关,因为缓存和主内存速度之间的差异(200x)以及连续的内存访问如何影响缓存使用。请参阅Chandler Carruth(谷歌)在此讨论此问题: https://www.youtube.com/watch?v=fHNmRkzxHWs
Mike Acton的数据导向设计在这里讲述: https://www.youtube.com/watch?v=rX0ItVEVjHc
答案 5 :(得分:2)
有关费用的详细信息,请参阅此问题:
What are the complexity Guarantees of the standard containers
如果你有一个slist,你现在想以相反的顺序遍历它,为什么不改变类型到任何地方列出?
答案 6 :(得分:0)
注意:如果您想了解有关性能的更多信息,我建议您查看this