数据结构之线性结构:从基础概念到实现细节
线性结构是数据结构中最基础也最常用的一类,其核心特征是数据元素之间存在一对一的线性关系。常见的线性结构包括线性表(顺序表、链表)、队列、栈等。它们在逻辑上形成一条 “直线”,每个元素(除首尾外)有唯一的前驱和后继。
线性结构的核心特征
线性结构的元素间关系可概括为:
- 存在唯一的 “首元素”(第一个元素)和 “尾元素”(最后一个元素)。
- 除首元素外,每个元素有且仅有一个 “前驱”(前一个元素)。
- 除尾元素外,每个元素有且仅有一个 “后继”(后一个元素)。
这种结构使得数据的遍历可以按线性顺序依次进行(如从首到尾)。
线性表:线性结构的基础
线性表是由零个或多个数据元素组成的有限序列,是线性结构的抽象模型。根据存储方式的不同,线性表可分为顺序表(顺序存储)和链表(链式存储)。
1. 顺序表(Sequential List)
顺序表是用连续的存储空间存储元素的线性表,逻辑上的顺序与物理存储顺序一致(类似数组)。
实现原理
- 底层依赖数组,元素在内存中连续排列,通过下标直接访问。
- 容量固定(可动态扩容),元素个数(
size)≤ 容量(capacity)。
核心操作及时间复杂度
| 操作 | 实现逻辑 | 时间复杂度 |
|---|---|---|
| 访问(get) | 通过下标直接定位元素 | O(1) |
| 插入(add) | 若插入中间位置,需移动后续元素腾出空间 | O(n) |
| 删除(remove) | 若删除中间元素,需移动后续元素填补空位 | O(n) |
| 扩容(ensureCapacity) | 复制原数组到更大的新数组 | O (n)(触发时) |
优缺点
- 优点:
- 访问速度快(O (1)),适合频繁查询的场景。
- 无需额外存储指针,空间利用率高。
- 缺点:
- 插入 / 删除需移动大量元素,效率低(O (n))。
- 初始容量难以确定,过小易溢出,过大浪费空间。
代码示例解析(Java)
1 | public class ShunXuBiao<T> { |
2. 链表(Linked List)
链表是用非连续的存储空间存储元素的线性表,元素(节点)通过指针(引用)关联,形成逻辑上的顺序。
节点结构
每个节点包含两部分:
data:存储元素值。next:指向后继节点的引用(单链表);双向链表还包含prev(指向前驱节点)。
常见类型
- 单链表:每个节点仅含
next指针,尾节点next为null。 - 双向链表:每个节点含
prev和next指针,可双向遍历。 - 循环链表:尾节点
next指向头节点,形成环,可从任一节点遍历全表。
核心操作及时间复杂度
| 操作 | 实现逻辑 | 时间复杂度 |
|---|---|---|
| 访问(get) | 从表头遍历到目标位置 | O(n) |
| 插入(add) | 找到插入位置,修改前后节点的指针 | O (1)(已知位置时) |
| 删除(remove) | 找到删除位置,修改前后节点的指针 | O (1)(已知位置时) |
优缺点
- 优点:
- 插入 / 删除效率高(O (1),已知位置时),无需移动元素。
- 无需预分配空间,元素个数可动态增长。
- 缺点:
- 访问效率低(O (n)),需从头遍历。
- 每个节点需额外存储指针,空间开销略大。
单链表代码示例解析(Java)
1 | public class LianBiao<E> { |
顺序表 vs 链表:关键对比
| 维度 | 顺序表 | 链表 |
|---|---|---|
| 存储方式 | 连续内存数组 | 非连续节点 + 指针 |
| 访问效率 | O (1)(下标直接访问) | O (n)(需遍历) |
| 插入 / 删除效率 | O (n)(需移动元素) | O (1)(已知位置时) |
| 空间利用率 | 无额外开销,但可能浪费空间 | 需存储指针,空间开销略大 |
| 动态扩容 | 需要复制数组(O (n)) | 无需扩容,动态增长 |
队列(Queue):先进先出的线性表
队列是仅允许在一端插入、另一端删除的特殊线性表,遵循 “先进先出(FIFO,First In First Out)” 原则。
核心概念
- 队尾(rear):允许插入元素的一端。
- 队头(front):允许删除元素的一端。
- 空队列:不含任何元素的队列。
基本操作
- 入队(enqueue):在队尾添加元素。
- 出队(dequeue):从队头移除元素。
- peek :查看队头元素(不删除)。
实现方式
- 顺序队列:基于数组实现,需处理 “假溢出”(可通过循环队列优化)。
- 链式队列:基于链表实现,队头为头节点,队尾为尾节点。
应用场景
- 任务调度(如线程池任务队列)。
- 缓冲处理(如 IO 缓冲区)。
- 广度优先搜索(BFS)。
栈(Stack):后进先出的线性表
栈是仅允许在一端插入和删除的特殊线性表,遵循 “后进先出(LIFO,Last In First Out)” 原则。
核心概念
- 栈顶(top):允许插入和删除的一端。
- 栈底(bottom):固定的一端,不允许操作。
- 空栈:不含任何元素的栈。
基本操作
- 入栈(push):在栈顶添加元素。
- 出栈(pop):从栈顶移除元素。
- peek :查看栈顶元素(不删除)。
实现方式
- 顺序栈:基于数组实现,栈顶指针跟踪栈顶位置。
- 链式栈:基于链表实现,栈顶为头节点。
应用场景
- 函数调用(调用栈)。
- 表达式求值(后缀表达式)。
- 括号匹配校验。
- 深度优先搜索(DFS)
v1.3.10