C++ 向量和列表插入

Posted

技术标签:

【中文标题】C++ 向量和列表插入【英文标题】:C++ vector and list insertion 【发布时间】:2013-04-25 01:51:42 【问题描述】:

有人知道为什么将元素插入列表中间更快吗 而不是在向量的中间插入一个元素?

我更喜欢使用矢量,但如果可以的话,我会被告知使用列表。 任何人都可以解释为什么? 是否总是建议使用列表而不是向量?

【问题讨论】:

链表和数组的本质对于任何程序员(任何语言)来说都是必不可少的。我建议您获取good C++ book,它将回答这个问题(以及更多)。 【参考方案1】:

如果我逐字回答这个问题,查找数组的中间部分 (std::vector) 是一个简单的操作,您将长度除以 2,然后向上或向下舍入以获得索引。查找双向链表(std::list)的中间需要遍历所有元素。即使你知道它的大小,你仍然需要走过一半以上的元素。因此 std::vector 比 std::list 快,换句话说,一个是 O(1),另一个是 O(n)。

在已知位置插入需要对数组的相邻元素进行混洗,并仅在另一个节点中链接以获得双向链表,正如其他人在此处解释的那样。因此,使用 O(1) 的 std::list 比使用 O(n) 的 std::vector 快。

为了在正中间插入,我们有 O(1) + O(n) 的数组和 O(n) + O(1) 的双向链表,在中间插入 O(n ) 对于两种容器类型。所有这些都忽略了诸如 CPU 缓存和分配器速度之类的东西,它只是比较了“简单”操作的数量。总之,您需要了解如何使用容器。如果你真的在随机位置插入/删除了很多,std::list 可能会更好。如果您很少这样做,然后只读取容器,则 std::vector 可能会更好。如果你只有十个元素,那么所有的 O(x) 都可能毫无价值,你应该选择你最喜欢的那个。

【讨论】:

【参考方案2】:

插入向量的中间需要将插入点之后的所有元素随机排列以腾出空间,这可能涉及大量复制。

列表实现为链表,每个节点在内存中占用自己的空间并引用相邻节点,因此添加新节点只需更改 2 个引用以指向新节点。

根据您使用的数据类型,向量的执行速度可能比列表快得多。但是要复制的对象越复杂,向量就越糟糕。

【讨论】:

【参考方案3】:

简单来说,向量就是一个数组。因此,它的元素存储在连续的内存位置(即,一个接一个)。唯一的例外是向量允许在运行时调整大小,而不会导致数据丢失。

现在,要插入列表,您需要识别节点,然后创建新元素(内存中的任何位置)、存储值并连接指针。

但是在向量(数组)的情况下,您必须将元素从一个单元格物理移动到另一个单元格,以便为新元素创建该空间。这种物理移动是导致延迟的原因,尤其是在需要移动许多元素(即数据)的情况下。您不是在物理上移动数组元素。相反,它的内容。

【讨论】:

@ValekHalfHeart 在 C++ 中,std::vector 是使用底层动态分配数组实现的。该标准的要求使其成为唯一可能的实施方式。【参考方案4】:

Ulrich Eckhardt 的回答非常好。我没有足够的声誉来添加评论,所以我会自己写一个答案。就像 Ulrich 所说的,列表和向量在中间的插入速度在理论上都是 O(n)。在实践中,现代 CPU 有一个叫做“预取器”的东西。它非常擅长获取连续数据。由于向量在内存中是连续的,因此由于预取器,移动大量元素非常快。您需要操作非常非常大的向量,以使它们的插入速度比列表慢。有关更多详细信息,请查看这篇很棒的博客文章:

http://gameprogrammingpatterns.com/data-locality.html

【讨论】:

以上是关于C++ 向量和列表插入的主要内容,如果未能解决你的问题,请参考以下文章

C++ 对向量或链表进行排序

在 C++ 中,在地图中插入一个向量

无法将元素插入到列表的向量中

为啥在达到容量后在向量中进行插入时,C++ 不处理迭代器?

在插入向量 C++ 之前验证用户输入

无法将集合的元素插入C++中的向量