【问题标题】:Linked List vs Vector链表与向量
【发布时间】:2013-10-03 02:44:25
【问题描述】:

在过去的几天里,我一直在为软件开发工作的第一次电话面试做准备。在研究问题时我提出了this article.

在我读到这段话之前,一切都很棒,

“你什么时候会使用链表和向量?”

现在从经验和研究来看,这是两种截然不同的数据结构,链表是动态数组,向量是空间中的二维点。我可以看到两者之间的唯一相关性是如果您使用向量作为链表,例如myVector(my value, pointer to neighbor)

想法?

【问题讨论】:

标签: data-structures vector linked-list


【解决方案1】:

我知道这个提问者有点晚了,但这是一个非常有见地的视频,来自 Bjarne Stroustrup(C++ 的发明者)关于为什么你应该避免使用现代硬件的链表。 https://www.youtube.com/watch?v=YQs6IC-vgmo 随着当今计算机上的快速内存分配,创建带有更新项目的向量副本的速度要快得多。

【讨论】:

  • 嗨乔纳森,当在答案中引用链接时,请尝试包含用户通过点击链接可能会发现的内容的摘要。请记住,链接可能会断开。未来证明你的答案。 How to Answer
  • 我真的不认为这个视频是列表和矢量类型之间的公平比较。谬误是通过在随机生成的 index 处删除单个元素时比较两者的效率。一个更有趣的比较是比较删除随机选择的成员的效率。我想知道需要从列表中删除多少百分比的成员才能使其表现优于向量。换句话说,用 [0, n) 范围内的 m 个随机整数填充一个列表和向量。然后删除所有的 0。对于 (m, n) 的哪些值,列表更有效?
【解决方案2】:

我不喜欢这里的第一答案,所以我想我会分享一些由 Microsoft 的 Herb Sutter 进行的实际研究。测试的结果是在一个容器中最多包含 100k 个项目,但它还声称它会继续在 50 万个实体上执行链表。除非您计划让您的容器拥有 数百万 个实体,否则 您的动态容器的默认容器应该是向量。我或多或少地总结了什么他说,但也会在底部链接参考:

"[即使]你在一个链表中预先分配节点,这会给你一半的性能,但它仍然[比向量]更差。为什么?首先它有更多的空间——每个元素的开销(是部分原因)——链表中涉及的前向和后向指针——还有(更重要的是)访问顺序。链表必须遍历以找到一个插入点,完成所有这些指针追逐,这与向量正在做的事情相同,但实际发生的是 预取器是如此之快。使用在内存中有效映射的数据执行线性遍历(例如,分配和使用指针向量定义和布局),它几乎在所有场景中都优于链表。”

https://youtu.be/TJHgp1ugKGM?t=2948

【讨论】:

  • 为什么向量必须在这里进行线性搜索才能访问元素。它只是可以在内存中连续布局的情况下以恒定的时间跳转到元素。
【解决方案3】:

作为对链表中插入和删除的大 O 时间的更正,如果您有一个保存当前元素位置的指针,以及用于在链表中移动它的方法,(如.moveToStart().moveToEnd(), .next() 等),您可以在恒定时间内删除和插入。

【讨论】:

    【解决方案4】:

    除非“数据量很大”或“必须有强大的安全保证”,否则请使用向量。

    数据量很大 :- 在中间插入向量需要线性时间(因为需要随机播放),但其他都是恒定时间操作(如遍历到第 n 个节点)。因此,如果数据量很小,则没有太多开销。

    根据“Andrei Alexandrescu 和 Herb Sutter 的 C++ 编码标准书”

    “对小列表使用向量几乎总是优于使用列表。即使在序列中间插入对于向量来说是线性时间操作,对于列表来说是恒定时间操作,但当容器时,向量通常优于列表相对较小,因为它具有更好的常数因子,并且列表的 Big-Oh 优势在数据量变大之前不会发挥作用。”

    强大的安全保障 列表提供强大的安全保障。 http://www.cplusplus.com/reference/list/list/insert/

    【讨论】:

      【解决方案5】:

      向量是dynamic arrays 的另一个名称。它是用于dynamic array data structure in C++ 的名称。如果你有 Java 方面的经验,你可能知道他们的名字是ArrayList。 (Java 还有一个名为 Vector 的旧集合类,由于其设计方式存在问题,现在已不再使用。)

      向量适用于随机读取访问以及后面的插入和删除(需要摊销的常数时间),但不适合前面或任何其他位置的插入和删除(线性时间,因为必须移动项目)。向量通常在内存中连续布局,因此遍历一个是高效的,因为 CPU 内存缓存得到有效利用。

      另一方面,Linked lists 适用于在前面或后面插入和删除项目(恒定时间),但对其他很多方面不是特别好:例如删除列表中间任意索引处的项目需要线性时间,因为您必须首先找到节点。另一方面,一旦你找到了一个特定的节点,你可以在恒定时间内删除它或在它之后插入一个新项目,这是矢量无法做到的。链表也很容易实现,这使得它们成为一种流行的数据结构。

      【讨论】:

      • 向量允许在 O(n) 时间内在中间插入和删除,就像链表一样。该算法在插入/删除位置和之后移动元素,这使其成为 O(n)。
      • 链表非常擅长中间的插入和删除。在链表中间插入是 O(1) 时间。另外,链表保证数据的地址在插入或删除其他数据时不会改变。
      • @cluracan,在链表中间插入或删除项目需要首先迭代列表以找到插入或删除点。正是这种迭代使得算法 O(n);如果您已经找到要插入/删除的项目,那么它当然是 O(1)。
      • @joni,你错了。记住列表的迭代器并不会使它成为“不是列表的其他东西”。它仍然是一个列表,我只有一个包含迭代器的变量。查找元素编号n 在链表中需要 O(n) 时间,但插入需要 O(1)。插入不必在它之前有“查找”,因为您可以通过其他方法选择插入的位置(例如记住您之前想要的)。无论如何——不管你怎么称呼它,它是你可以用链表做的,但不能用向量做的事情。
      • @joni 所以你必须把它放在“链表优于向量的优势”中,不是吗?因为它是链表优于向量的优势......
      猜你喜欢
      • 2015-02-17
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 1970-01-01
      相关资源
      最近更新 更多