ScholarGate
助手

数组和链表

数组和链表是存储有序元素序列的两种基本方式:数组将元素存储在连续内存中,以实现常数时间索引访问,而链表通过指针将元素链接起来,以实现廉价的插入和删除。

用 PaperMind 寻找选题即将推出Find papers & topics
Tools & resources
下载幻灯片
Learn & explore
视频即将推出

Definition

数组将元素存储在按位置索引的连续内存位置中,允许常数时间随机访问;链表将元素存储在单独的节点中,每个节点都包含对下一个(以及可能的前一个)节点的引用,允许在给定节点引用的情况下进行常数时间插入或删除。

Scope

本主题涵盖线性、基于序列的结构及其上构建的抽象数据类型——静态和动态数组、单向和双向链表,以及栈和队列ADT。它对比了它们的访问、插入和删除成本,涵盖了动态数组的重新调整大小及其摊销分析,并解释了内存布局后果,例如缓存局部性。它不包括散列表和搜索树中涵盖的关联和层次结构。

Core questions

  • 连续(数组)存储何时优于指针链接(列表)存储?
  • 动态数组如何通过偶尔的重新调整大小实现摊销常数时间追加?
  • 数组与链表在插入、删除和访问方面的成本权衡是什么?
  • 栈和队列是如何在这些结构之上实现的?
  • 内存布局如何通过缓存行为影响实际性能?

Key concepts

  • 连续内存
  • 索引访问
  • 动态数组调整大小
  • 单向和双向链表
  • 栈(LIFO)
  • 队列(FIFO)
  • 摊销成本
  • 缓存局部性

Key theories

随机访问与顺序链接
数组支持O(1)索引访问,但在中间插入或删除为O(n),而链表在给定节点的情况下支持O(1)拼接,但按位置访问为O(n);正确的选择取决于操作组合。
动态数组的摊销增长
当动态数组满时将其容量加倍,会偶尔执行O(n)的复制操作,但通过聚合或势能法,在任何操作序列中,每次追加的摊销成本为O(1)。

Clinical relevance

数组和列表几乎是每个程序的基石:动态数组实现了大多数语言中的默认列表/向量类型,队列是调度和广度优先搜索的基础,栈是函数调用管理和表达式求值的基础,而数组与列表的权衡是影响性能的常规实际设计决策。

History

数组是最早的数据结构之一,存在于第一批编程语言中,而链表则是在1950年代后期为符号和列表处理(尤其是在Newell、Shaw和Simon的IPL以及后来的Lisp中)引入的。高德纳(Knuth)在《计算机程序设计艺术》中对它们的系统处理确立了其规范分析。

Key figures

  • Donald Knuth
  • Robert Sedgewick

Related topics

Seminal works

  • knuth1997vol1
  • cormen2009

Frequently asked questions

如果数组支持快速随机访问,为什么还要使用链表?
链表在给定节点引用的情况下,允许在常数时间内插入或删除,而无需移动其他元素,这是数组在中间无法做到的。当序列频繁变化且不需要按位置随机访问时,链表非常有用。
如果调整大小会复制所有内容,为什么数组追加被认为是常数时间?
调整大小很少发生,因为容量通常会翻倍,因此在n次追加操作中,总的复制工作量与n成比例。分摊到所有追加操作中,即使单个调整大小是O(n),每次追加的摊销成本也是常数。

Methods for this concept

Related concepts