Files
test-repo/docs/zh-cn/appendix/1-computer-fundamentals/data-structures.md
T

231 lines
7.9 KiB
Markdown
Raw Normal View History

# 数据结构
::: tip 前言
**如何高效地组织和存储数据?** 你可能遇到过这样的困惑:为什么有些程序处理几万条数据很快,有些处理几百条就卡住了?答案往往在于数据结构的选择。本章带你理解常见数据结构的特点和适用场景。
:::
**这篇文章会带你学什么?**
学完这章后,你将获得:
- **选型决策能力**:知道什么时候用数组快速访问,什么时候用链表灵活插入
- **性能分析视角**:能判断性能问题是数据结构选择不当,还是算法效率低下
- **权衡思维**:理解"空间换时间"与"时间换空间",知道没有完美的数据结构
- **后续学习基础**:为数据库、缓存系统、搜索引擎等技术打下基础
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 线性结构 | 数组、链表、栈、队列 |
| **第 2 章** | 哈希结构 | 哈希表、冲突处理 |
| **第 3 章** | 树形结构 | 二叉树、B树、堆 |
| **第 4 章** | 图结构 | 有向图、无向图、遍历算法 |
---
## 0. 全景图:数据结构是什么?
想象你要整理一堆书:
- **堆在地上**:找书要一本本翻(链表)
- **按编号放书架**:直接去对应位置拿(数组)
- **按类别分柜子**:先找柜子再找书(哈希表)
- **按书名排序**:二分查找,每次排除一半(树)
不同的整理方式,找书的效率天差地别。**数据结构就是数据的"整理方式"**。
<DataStructureDemo />
**常见数据结构分类:**
| 类型 | 特点 | 典型代表 | 适用场景 |
|------|------|---------|---------|
| **线性结构** | 数据排成一排 | 数组、链表、栈、队列 | 顺序处理、历史记录 |
| **哈希结构** | 键值对映射 | 哈希表 | 快速查找、缓存 |
| **树形结构** | 层次关系 | 二叉树、B树 | 排序、搜索、文件系统 |
| **图结构** | 网状关系 | 有向图、无向图 | 社交网络、路径规划 |
::: tip 📊 逐行解读这张表
**线性结构**:最简单的数据组织方式,数据一个接一个排列。数组适合随机访问,链表适合频繁插入删除。
**哈希结构**:用"键"直接找到"值",查找速度最快。但需要处理"冲突"问题(两个键映射到同一位置)。
**树形结构**:有层次关系的数据。二叉搜索树适合排序和搜索,B树适合磁盘存储(数据库索引)。
**图结构**:最复杂的结构,表示任意的关系网络。社交网络、地图导航都用图来建模。
:::
---
## 1. 线性结构:最基础的组织方式
### 1.1 数组:连续存储
::: tip 💡 数组的特点
**数组**是一块连续的内存空间,每个元素大小相同。
**优点**
- 随机访问快:`arr[100]` 直接计算地址,O(1)
- 缓存友好:连续存储,CPU 缓存命中率高
**缺点**
- 插入删除慢:需要移动后面所有元素,O(n)
- 大小固定:需要预先分配空间
**生活类比**:一排编号的储物柜,每个柜子大小相同。找第 10 号柜子直接去,但要在中间插入一个柜子,后面的都要往后挪。
:::
### 1.2 链表:节点相连
::: tip 💡 链表的特点
**链表**由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
**优点**
- 插入删除快:只需修改指针,O(1)
- 大小灵活:可以动态增长
**缺点**
- 访问慢:要从头开始遍历,O(n)
- 额外空间:每个节点需要存储指针
**生活类比**:寻宝游戏,每个线索指向下一个地点。要找第 10 个线索,必须从第 1 个开始一步步找。
:::
### 1.3 栈和队列:受限的线性结构
| 结构 | 规则 | 操作 | 类比 | 应用 |
|------|------|------|------|------|
| **栈** | 后进先出 (LIFO) | push/pop | 一摞盘子 | 函数调用、撤销操作 |
| **队列** | 先进先出 (FIFO) | enqueue/dequeue | 排队买票 | 任务调度、消息队列 |
::: tip 💡 为什么要有"受限"的结构?
栈和队列看起来比数组、链表功能少,但正是这种"限制"让它们有明确的用途:
- **栈**:函数调用时,最后调用的函数最先返回
- **队列**:任务调度时,先来的任务先处理
限制带来简洁,简洁带来高效。
:::
---
## 2. 哈希表:最快的查找
### 2.1 哈希表原理
::: tip 💡 哈希表如何工作?
**哈希表**通过"哈希函数"把键映射到数组索引。
**工作流程**
1. 输入键(如 "apple"
2. 哈希函数计算:`hash("apple") = 3`
3. 直接去数组索引 3 的位置找
**冲突处理**
- 两个不同的键可能映射到同一索引
- 解决方法:链地址法(同一位置用链表存储多个值)
**生活类比**:图书馆按书名首字母分柜子。"Apple" 开头的书都放 A 柜,"Banana" 开头的放 B 柜。找书时先确定柜子,再在柜子里找。
:::
### 2.2 哈希表的时间复杂度
| 操作 | 平均情况 | 最坏情况 |
|------|---------|---------|
| **查找** | O(1) | O(n) |
| **插入** | O(1) | O(n) |
| **删除** | O(1) | O(n) |
::: warning ⚠️ 什么时候会退化?
当所有键都映射到同一个索引时,哈希表退化为链表,所有操作变成 O(n)。
**避免方法**
- 选择好的哈希函数
- 动态扩容(负载因子超过阈值时扩容)
:::
---
## 3. 树:层次结构
### 3.1 二叉搜索树
::: tip 💡 二叉搜索树的规则
**二叉搜索树**是一种特殊的二叉树:
- 左子树的所有值 < 根节点
- 右子树的所有值 > 根节点
**查找过程**
1. 从根节点开始
2. 如果目标值 < 当前值,往左走
3. 如果目标值 > 当前值,往右走
4. 每次比较排除一半节点
**时间复杂度**:O(log n),但最坏情况(变成链表)是 O(n)
:::
### 3.2 平衡树
为了防止二叉搜索树退化,引入了**平衡树**:
| 类型 | 平衡方式 | 特点 |
|------|---------|------|
| **AVL 树** | 严格平衡(高度差 ≤ 1) | 查找最快,插入删除稍慢 |
| **红黑树** | 近似平衡 | 综合性能好,应用最广 |
| **B 树** | 多路平衡 | 适合磁盘存储,数据库索引 |
---
## 4. 如何选择数据结构?
| 需求 | 推荐结构 | 原因 |
|------|---------|------|
| **快速随机访问** | 数组 | O(1) 索引访问 |
| **频繁插入删除** | 链表 | O(1) 插入删除 |
| **快速查找** | 哈希表 | O(1) 平均查找 |
| **有序数据** | 平衡树 | O(log n) 查找,保持有序 |
| **最近使用** | 栈 | LIFO 特性 |
| **任务排队** | 队列 | FIFO 特性 |
::: tip 💡 选择数据结构的心法
**没有最好的数据结构,只有最合适的数据结构。**
选择时要考虑:
1. **主要操作是什么?** 查找?插入?删除?
2. **数据量多大?** 小数据量差别不大,大数据量要慎重
3. **数据有序吗?** 有序数据可以用二分查找
4. **内存限制?** 某些结构需要额外空间
:::
---
## 5. 总结:数据结构是程序的基础
让我们用一个比喻总结各种数据结构:
| 结构 | 比喻 | 核心特点 |
|------|------|---------|
| **数组** | 编号储物柜 | 访问快,插入慢 |
| **链表** | 寻宝线索 | 插入快,访问慢 |
| **栈** | 一摞盘子 | 后进先出 |
| **队列** | 排队队伍 | 先进先出 |
| **哈希表** | 分类柜子 | 查找最快 |
| **树** | 家族族谱 | 层次结构 |
::: tip 💡 核心启示
**数据结构决定了程序的效率上限。**
- 选对数据结构,问题迎刃而解
- 选错数据结构,再好的算法也无济于事
理解数据结构,就是理解"如何高效地组织数据"。这是每个程序员的基本功。
:::
---
## 延伸阅读
- **数据结构实现**:自己动手实现各种数据结构,加深理解
- **高级数据结构**:学习跳表、布隆过滤器、并查集等
- **数据库索引**:了解 B+ 树在数据库中的应用
- **缓存设计**:学习 LRU 缓存如何结合哈希表和链表