我使用了很多列表和数组,但我还没有遇到过一个场景,在这个场景中,链表比起数组列表来说能更容易地被使用,或者说更加优越。我希望有人能给我一些示例,说明何时使用链表会更加明显优于使用数组列表。
我使用了很多列表和数组,但我还没有遇到过一个场景,在这个场景中,链表比起数组列表来说能更容易地被使用,或者说更加优越。我希望有人能给我一些示例,说明何时使用链表会更加明显优于使用数组列表。
链表在以下情况下优于数组:
需要常数时间的列表插入/删除(例如在实时计算中,时间可预测性非常关键)
不知道列表中会有多少项。使用数组时,如果数组变得太大,可能需要重新声明和复制内存。
不需要任何元素的随机访问
要能够在列表中间插入项目(例如优先级队列)
数组在以下情况下优于链表:
需要对元素进行索引/随机访问
预先知道数组中元素的数量,以便可以为数组分配正确数量的内存
需要迭代按顺序遍历所有元素时速度更快。您可以在数组上使用指针数学来访问每个元素,而在链表中,您需要基于指针查找每个元素的节点,这可能导致页面故障,从而影响性能。
关注内存。填充的数组比链接列表占用更少的内存。数组中的每个元素只是数据。每个链表节点都需要数据以及指向链接列表中其他元素的一个或多个指针。
数组列表(例如 .Net 中的ArrayList)使您可以获得数组的好处,但动态为您分配资源,因此您不需要太担心列表大小,而且可以轻松删除任何索引处的项目或重新排列元素。从性能上讲,数组列表比原始数组慢。
数组具有 O(1) 的随机访问能力,但在添加或移除元素时的成本非常高。
链表添加或删除任意位置的元素和迭代都非常便宜,但随机访问的成本为O(n)。
Algorithm ArrayList LinkedList
seek front O(1) O(1)
seek back O(1) O(1)
seek to index O(1) O(N)
insert at front O(N) O(1)
insert at back O(1) O(1)
insert after an item O(N) O(1)
ArrayList(数组列表)适用于写一次读多次或者追加操作,但在从头部或中间添加/删除操作上表现较差。
O(1)
。否则,您将不得不迭代链表直到找到正确的位置,这将是O(N)
。 - Ricky Sixx除了其他回答所述,大多数数组列表实现在列表末尾保留额外的容量,以便可以在O(1)时间内向列表末尾添加新元素。当数组列表的容量超过限制时,内部会分配一个新的、更大的数组,并将所有旧元素复制到其中。通常,新数组的大小是旧数组的两倍。这意味着,在这些实现中,平均而言,向数组列表末尾添加新元素是一个O(1)操作。因此,即使您不知道元素的数量,只要您在末尾添加它们,数组列表可能仍然比链表更快。显然,在任意位置插入新元素到数组列表仍然是一个O(n)操作。
即使访问是顺序的,访问数组列表中的元素也比访问链表更快。这是因为数组元素存储在连续的内存中,很容易被缓存。链表节点可能散布在许多不同的页面上。
我建议只在您知道将在任意位置插入或删除项目时才使用链表。对于几乎所有其他情况,数组列表都会更快。
实际上,内存局部性在实际处理中具有巨大的性能影响。
"大数据"处理中磁盘流式处理的增加与随机访问相比表明,围绕此结构化应用程序可以在更大的规模上显着提高性能。
如果有任何一种方法可以按顺序访问数组,那么这是最好的性能。如果性能很重要,设计时应考虑这个目标。
这些是Collection最常用的实现方式。
ArrayList:
一般情况下在末尾插入/删除操作的时间复杂度为O(1),最坏情况为O(n)。
在中间插入/删除操作的时间复杂度为O(n)。
任意位置检索的时间复杂度为O(1)。
LinkedList:
在任意位置插入/删除(如果你有元素的引用)操作的时间复杂度为O(1)。
在中间检索的时间复杂度为O(n)。
检索第一个或最后一个元素的时间复杂度为O(1)。
Vector:不要使用它。它是类似于ArrayList的旧实现,但所有方法都是同步的。在多线程环境中,这不是正确的共享列表的方法。
HashMap
按键插入/删除/检索的时间复杂度为O(1)。
TreeSet
按顺序插入/删除/包含的时间复杂度为O(log N)。
HashSet
插入/删除/包含/大小的时间复杂度为O(1)。
数组是目前最广泛使用的数据结构。然而,在数组笨重或昂贵的情况下,链表以其独特的方式证明了自己的用处。
在大小可能变化的情况下,链表可用于实现堆栈和队列。链表中的每个节点都可以被推入或弹出,而不会干扰大多数节点。对于在中间插入/删除节点也是如此。然而,在数组中,所有元素都必须进行移位,这在执行时间方面是一项昂贵的工作。
二叉树和二叉搜索树、哈希表和字典树是一些数据结构,其中至少在C语言中,需要链表作为构建它们的基本组成部分。
然而,在期望能够通过索引调用任意元素的情况下,应避免使用链表。