什么时候应该使用向量/列表?


17

我可以理解何时使用列表,但是不知道何时使用向量比在视频游戏中使用列表更好:何时可以进行快速随机访问?

(而且我知道为什么在列表中插入/删除会更快,因为它只是删除/添加了指针,但仍然必须找到对应的项目...)


重新添加矢量标签到此-如果列表是有效标签,则矢量也是如此。
Kylotan

大概矢量被删除了,因为它用来表示数学矢量,而不是std :: vector。

1
把它们都放进去怎么样container
deft_code 2011年

@Kylotan:就像乔说的。这个问题肯定是关于向量的,但是它不属于向量标签。
doppelgreener 2011年

1
那么,我们是否要删除任何不明确的标签?对于我来说,这听起来像是一个错误的决定-最好是您的搜索显示的信息太多而不是不足。跳过不需要的结果比集思广益来查找同义词要容易得多。
Kylotan

Answers:


29

我的经验法则是,永远不会使用列表(除非您需要非常非常频繁地从大列表的中间删除内容),而且我敢肯定会对此进行辩论。

通过将容器中的所有元素都放在连续的内存中(因此更加便于缓存)而获得的速度值得抵消添加/删除/调整向量大小的额外费用。

编辑:只是要澄清一点,当然应该不言而喻,应该在具有任何与您的特定需求相关的任何数据集的平台上测试任何一种“更快”的问题。如果我只需要一个元素集合,那么除非有充分的理由不这样做,否则我只会使用vector(或deque,这几乎是同一件事)。


1
我认为这很大程度上取决于您的需求,如果您永远不需要访问特定元素,而只需要阅读所有元素,并且经常添加和删除元素,则列表是一个更好的解决方案。
弗雷德里克Imbeault

11
@Frédérick:这是标准的C ++智慧,但这几乎总是错误的。向量,尤其是在处理指针向量(您几乎总是在游戏中)时,从中间删除内容的速度非常快-这是线性时间,但是每个项目的开销非常小。这也是很多更快地迭代顺序在一个载体。

1
我不确定您要获得什么样的结构-这种优化需要具体的例子明确地说出什么。例如,我对您的用例的第一反应是一个无序集合,它允许同样快速的插入,删除和查找。根据我的经验,集非常适合编辑器中的对象。但是由于编辑者对实时性能的要求更高-例如,如果响应“删除”按钮,则需要10%的时间花费1/20秒或1/2秒的时间-这是最优化的水平也很少适用于他们。

1
@FrédérickImbeault修改不是什么大问题,而是Add \ Remove会引起问题。从添加\删除点到向量的末尾被复制以保持向量连续。如果元素顺序无关紧要,则可以将删除的元素与最后一个元素交换,然后弹出该元素以进行删除,然后添加到末尾以进行添加。
stonemetal

4
可以肯定的是,获取向量中元素的地址并将其存储起来是不安全的。但总的来说,您几乎从来没有这样做,而是更喜欢使用元素指针的向量来复制指针(或类似的东西)。
Tetrad 2010年

8

当由于修改数据结构的中间部分而导致的迭代器无效将导致问题时,请使用一个列表,或者您需要对元素进行排序,以便快速删除中间集合的swap和pop技巧将不起作用,并且您的数据量很大中间集合删除次数。

您可能还需要考虑使用双端队列。它具有与向量类似的性能特征,但不需要向量对连续内存的需求,并且灵活性更高。


+1是唯一提及双端队列的人-您可以获得向量的连续内存和查找速度优势,并且两端都有快速插入/删除操作。

5

您的选择应反映您的需求。向量的所有元素在内存中都是连续的,并且列表具有指向next / previous元素的指针,因此它们每个都有其优势/劣势:

清单:

  • 每个元素需要2个整数来指向上一个和下一个元素,因此最常见的是,列表中每个元素多8个字节
  • 插入时间是线性的:O(n)
  • 删除是一个常量操作:O(1)
  • 访问x元素在时间上是线性的:O(n)

向量:

  • 需要更少的内存(没有指向其他元素的指针,这是一个简单的数学算法)
  • 移除时间线性:O(n)
  • 访问x元素是常量:O(1)(这是因为元素在内存中是连续的,所以它是一个简单的数学运算vectorPtr +(x * bytesOfTheType))
  • 插入可以是线性时间,但最常见的是固定操作:O(1)(这是因为数组中的向量在数组已满时总是保留其容量的2倍,因此不经常复制数组)

因此,当您的程序需要经常添加和删除元素,但是从不访问(或很少访问)特定元素而不需要其他元素时,list会更好。应该使用向量来缩短访问时间,但是当您需要删除或添加元素时缺乏效率。

查看有关stackoverflow的这篇文章,它提供了一个非常不错的图表,其中包含有关您的需求的基本问题,根据您的答案将您带到特定的容器:

/programming/366432/extending-stdlist


3
该图确实需要从“您存储的指针是否少于一千个?否->向量”节点开始。

是的,也许您是对的,我不认为应该对存储的类型进行分析。
弗雷德里克Imbeault

2

通常,列表用于诸如队列之类的结构,其中有大量的添加和删除操作。例:不断变化的应更新实体列表。列表本身仅包含屏幕上的实体,因此经常更改。

向量(或数组)更适合于变化不大且需要快速访问集合中各个项目的集合。示例:必须在给定索引处查找图块的图块地图。

Tetrads的观点可能是正确的,但这取决于所使用的编程语言。我看到您标记了您的问题c++,但我尝试给出的答案并非特定于语言。


好吧,我可能也将C放入其中,但是C中没有这样的容器,但这是要考虑的问题:C是否有一些类似于STL的库?
jokoon

过去我曾经使用过glib(library.gnome.org/devel/glib),它为C实现了许多标准数据结构。我讨厌它,因为它通常太冗长并且非常想成为C ++,但它已经成熟并且稳定。

0

在主机游戏中,我们永远不会使用std :: list,因为:

  1. 每当您添加新项目时,它都会进行内存分配。内存分配很慢。
  2. 它充满了指针。指针不好。指针是高速缓存未命中。高速缓存未命中是不好的。

甚至std :: vector在控制台上也失去了支持,因为:

  1. 例如,您通常只关心所有对象的位置。例如,您想使对象彼此碰撞,在这种情况下,您无需关心它们的颜色是什么。因此,您希望所有位置在内存中都是连续的,并且希望颜色位于其他较远的地方,以避免污染缓存。但是std :: vector要求您将每个对象的所有内容都存储在连续的内存块中(例如,位置然后是颜色)。因此,如果您所做的工作仅读取位置,则还需要将所有颜色也读取到缓存中,即使如果您不使用它们。这很浪费。

5
@bmcnett“ [] ..但是std :: vector要求您将每个对象的所有内容都存储在连续的内存块中”-这不是容器的问题,它是数据布局的问题,您可以拥有所有位置在带有std :: vector的连续内存中:struct point{float x, y, z, w}; std::vector<point> positions;
Maik Semder 2011年

我的学校会喜欢这个:)
jokoon 2011年

2
-1,因为此答案尚未在列表中添加任何内容,而矢量讨论已在此处进行,正如Maik所说,它关于矢量污染缓存的说法是错误的。

你误解了我的主张。我从没说过在所有容器 std :: vector中特别有罪于缓存。所有的容器,实际上甚至是数组,都同样地有罪。std :: vector不受欢迎,因为C ++对象本身不受欢迎。C ++要求每个对象的数据在内存中是连续的。您可以通过避免使用C ++对象来解决此问题,例如通过使用上述std :: vector <position>来解决。
bmcnett 2011年

3
除了point是一个C ++对象(就像一样std::vector,就像一样简单float)。我知道您要画出的区别,但是您在解释它时做得很糟糕。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.