为什么链表比数组更快?

时间:2011-03-26 20:35:46

标签: arrays performance linked-list

我对此感到非常困惑。到处都写着“链表比数组更快”,但没有人愿意说出为什么。使用普通逻辑我无法理解链表如何更快。在一个数组中,所有单元格彼此相邻,因此只要您知道每个单元格的大小,就可以立即轻松到达一个单元格。例如,如果有一个包含10个整数的列表,并且我想在第四个单元格中获取该值,那么我只需直接到数组的开头+24个字节并从那里读取8个字节。

另一方面,如果你有一个链表并想要获得第四名的元素,那么你必须从列表的开头或结尾开始(取决于它是单列表还是双列表)并且去从一个节点到另一个节点,直到找到你要找的东西。

那么heck如何逐步进行比直接进入元素更快?

5 个答案:

答案 0 :(得分:13)

这个题目标题具有误导性。

它断言链接列表 比数组更快,而不会很好地限制范围。有很多次,数组可以显着更快,并且链接列表可以显着更快的次数:链接的特定情况列表“更快”似乎不受支持。

有两件事需要考虑:

  1. 特定操作中链接列表与数组的理论界限;和
  2. 现实世界的实施和使用模式,包括缓存局部性和分配。
  3. 对于索引元素的访问:操作在数组中是O(1) ,并且如所指出的那样,非常快(只是一个偏移量)。 操作在链接列表中为O(k) (其中k是索引,可能始终为<< n,视情况而定)如果链接列表已经遍历然后每步O(1)与数组“相同”。如果数组遍历for(i=0;i<len;i++)更快(或更慢)取决于特定的实现/语言/运行时。

    但是,如果存在特定的情况,其中数组对于上述任一操作(搜索或遍历)都不会更快,那么看到在更多的情况下被解剖将会很有趣细节。 (我确信有可能在列表中找到一种非常简并的数组实现语言 cough Haskell cough

    快乐的编码。


    我的简单用法摘要:数组适用于索引访问和涉及交换元素的操作。然而,非摊销的重新规模操作和额外的松弛(如果需要)可能相当昂贵。链接列表可以分摊重新调整大小(以及每个单元格的“指针”的交易松弛),并且通常可以在“切出或插入一堆元素”等操作中表现出色。最后,它们是不同的数据结构,应该这样对待。

答案 1 :(得分:7)

与编程中的大多数问题一样,上下文是所有。您需要考虑数据的预期访问模式,然后适当地设计存储系统。如果您插入一次,然后访问它1,000,000次,那么谁在乎插入成本是多少?另一方面,如果您在阅读时经常插入/删除,那么这些成本就会决定。

答案 2 :(得分:4)

取决于您所指的操作。在链表中添加或删除元素比在数组中快得多。

在链表和数组中,逐个顺序迭代列表的速度大致相同。

在数组中间获取一个特定元素要快得多。

并且数组可能会浪费空间,因为在扩展数组时,通常会在该时间点分配比所需更多的元素(想想Java中的ArrayList)。

因此,您需要根据自己的需要选择数据结构:

许多插入和顺序迭代 - &gt;使用LinkedList

随机访问,理想情况下是预定义的大小 - &gt;使用数组

答案 3 :(得分:3)

因为在数组中间插入时没有移动内存。 对于你提出的情况,它的真实 - 数组更快,你只需要算术从一个元素到另一个元素。链表需要间接和片段内存。 关键是要知道使用什么结构以及何时使用。

答案 4 :(得分:2)

在以下情况下,链接列表优于数组:

a)您需要从列表中进行恒定时间的插入/删除(例如在时间可预测性非常关键的实时计算中)

b)您不知道列表中有多少项。对于数组,如果数组变得太大,您可能需要重新声明和复制内存

c)您不需要随机访问任何元素

d)您希望能够在列表中间插入项目(例如优先级队列)

在以下情况下优先使用数组:

a)您需要对元素进行索引/随机访问

b)你提前知道数组中元素的数量,以便为数组分配正确的内存量

c)在按顺序迭代所有元素时需要速度。您可以在数组上使用指针数学来访问每个元素,而您需要根据链表中每个元素的指针查找节点,这可能会导致页面错误,从而导致性能下降。

d)记忆是一个问题。填充数组占用的内存少于链表。数组中的每个元素都只是数据。每个链表节点都需要数据以及指向链表中其他元素的一个(或多个)指针。

数组列表(如.Net中的那些列表)为您提供了数组的好处,但为您动态分配资源,因此您不必过多担心列表大小,并且可以删除任何索引处的项目而无需任何努力或重新洗牌的元素。性能方面,arraylists比原始数组慢。

参考: 拉马尔回答 https://stackoverflow.com/a/393578/6249148