P2-9.1 为什么需要数据结构¶
Section ID:
P2-9.1Version:v2026.07.20
在 P2-8 中,我们已经看过 Python 的值、列表、字典、循环、函数和类。现在我们后退一步,把问题换掉。
数据应该用什么形状来装?
这个问题就是数据结构的出发点。数据结构不只是语法名称。数据如何组织、哪些操作会被频繁执行,会一起改变代码的形状和计算的方式。
这里说明 data structure、abstract data type、linear structure、non-linear structure 这几个基本区分。即使后面的章节会再把数组、表、树、图分开来看,为什么要先把数据结构读成一个问题,仍然要回到本节的标准。后面这些结构名称再次出现时,也可以一起查看概念词汇表。
本节不是增加新的 Python 语法,而是从“数据组织”的视角,把前面学过的语法重新绑在一起。如果说 Chapter 8 是学习值、成组、重复、函数这些可执行语句的阶段,那么这里就是重新看这些语句默认依赖了什么样的数据形状。这样读,更容易把列表和字典理解成不同的数据结构选择,而不是单纯的语法项目。
| 本节现在要抓住的内容 | 紧接着会延伸到的问题 | 之后再次出现的位置 |
|---|---|---|
| 数据结构是同时看“数据的承载形状”和“操作方式”的视角 | 会延伸到 P2-9.2 中如何用问题来区分数组、表、树、图 | 之后会在 NumPy、Pandas、图表示、项目数据设计中反复出现 |
| 同一份数据也会因为目的不同而以列表、字典、图等不同形式保存 | 会延伸到判断哪一种结构更自然的标准 | 之后会在预处理、标签映射、关系数据、文档结构表示中再次使用 |
| Chapter 8 的语法节和 Chapter 9 的数据结构节不是同一类内容 | 这会让“问题已从语法复习转向数据结构直觉”变得更清楚 | 它会成为之后区分 Python 基础学习和数据结构学习的标准 |
| 术语 | 本节先要抓住的含义 |
|---|---|
| data structure | 决定如何组织和处理数据的方法 |
| operation | 在结构上经常执行的工作,如搜索、添加、删除、遍历 |
| abstract data type | 从行为视角定义“可以做什么”的框架 |
| linear structure | 把数据理解成沿着一条顺序线展开的结构 |
| non-linear structure | 不能只按一条线来读的结构,例如层级或关系 |
例如,即使是同样的学生分数数据,也会因为目的不同而变成不同结构。
问题场景:当你只想按顺序处理分数时,想先看最简单的结构。 输入(input):三个学生分数 82, 75, 91。 期望输出(output):分数列表 scores。 要确认的概念:列表是适合按顺序处理值的基本数据结构。
这种结构适合按顺序处理分数。
问题场景:当你想按学生姓名直接找到分数时,想看到为什么需要另一种结构。 输入(input):以姓名为键、分数为值的 score_by_name。 期望输出(output):按姓名组织的分数字典映射。 要确认的概念:即使是同样的数据,如果按姓名查找更重要,字典会更自然。
这种结构适合按姓名查找分数。
即使是同样的数据,适合的结构也会因为“按顺序看”“按姓名查找”“沿着关系追踪”而不同。
核心判断标准:为什么需要数据结构¶
- 能把数据结构解释成组织数据的方法。
- 能在入门层面解释线性结构与非线性结构的区别。
- 能说明数据结构会和搜索、添加、删除、遍历等操作连在一起。
- 能说明同一份数据会因目的不同而被表示成列表、字典、表、图等不同形式。
- 能在入门层面区分抽象数据类型与具体实现。
- 能说明在 AI 实践中,数据集、token 列表、标签映射、关系数据可能需要不同结构。
三个标准¶
本节不是让你背数据结构名称,而是让你问:数据该用什么形状来装? 下面这三个标准,会成为后面阅读数组、表、树、图说明时的基础。
| 标准 | 为什么重要 | 本节需要达到的理解程度 |
|---|---|---|
数据结构是 组织数据的方法 | 它让你从“用途”而不是“语法名称”来阅读 | 这是一个去问“顺序、标签、层级、关系里哪一个最重要”的章节 |
即使是同样的数据,也会因为 常做的操作 不同而需要不同结构 | 它帮助你理解为什么学完列表和字典后还要继续学更多结构 | 是按顺序看,还是按姓名查找,会让结构不同 |
抽象数据类型与实现不是 同一件事 | 它让你之后更稳妥地阅读栈、队列、图 | 行为规则和实际存储方式必须区分开 |
数据结构是组织信息的方式¶
NIST 的 Dictionary of Algorithms and Data Structures 把数据结构解释成“为了算法效率而组织信息的方式”。在这里,我们把数据结构理解成下面这样。
数据结构是一个把“承载数据的形状”和“处理数据的方式”一起考虑的概念。
列表(list)承载有顺序的值。
字典(dictionary)通过键来找值。
集合(set)关注无重复的包含关系。
树(tree)表示层级结构。
图(graph)表示对象之间的关系。
| 数据结构直觉 | 中心问题 | 例子 |
|---|---|---|
| 顺序 | 第几个值是什么? | 列表(list) |
| 标签 | 用哪个键来找? | 字典(dictionary) |
| 是否包含 | 在不在里面? | 集合(set) |
| 层级 | 有没有上下级关系? | 树(tree) |
| 关系 | 什么和什么相连? | 图(graph) |
选择数据结构,不是在选择“哪种语法更熟悉”,而是在选择“什么工作会被更频繁地执行”。
传统的数据结构导论会先展示什么¶
传统的数据结构导论通常会把“承载数据的形状”分成几个大方向来介绍。并不是每本教材都遵循同样顺序,但在前期你经常会遇到数组(array)、链表(linked list)、栈(stack)、队列(queue)、树(tree)、图(graph)、哈希表(hash table)等结构。
这些名称不是死记的清单,而是代表处理数据时常见的问题类型。
| 传统数据结构 | 入门问题 | 直观印象 |
|---|---|---|
| 数组(array) | 是否要用连续位置处理同类值? | 编号格子 |
| 链表(linked list) | 是否让值指向下一个值? | 串起来的项目 |
| 栈(stack) | 是否后放进去的先取出来? | 叠盘子 |
| 队列(queue) | 是否先进去的先取出来? | 排队 |
| 树(tree) | 是否存在父子关系? | 文件夹结构 |
| 图(graph) | 多个对象之间是否彼此相连? | 关系网 |
| 哈希表(hash table) | 是否要按键快速找到值? | 按标签找的收纳盒 |
这些结构还可以再大致分成线性结构(linear structure)和非线性结构(non-linear structure)。
线性结构是数据沿着一条顺序线排开的结构。数组、列表、栈、队列都接近这种情况。
非线性结构则不是只沿着一条线展开。树和图最具有代表性。树表达层级,图表达多方向关系。
| 分类 | 特征 | 例子 |
|---|---|---|
| 线性结构(linear structure) | 前后顺序重要 | 数组、链表、栈、队列 |
| 非线性结构(non-linear structure) | 层级或关系重要 | 树、图 |
| 基于键的结构(key-based structure) | 按键找值很重要 | 字典、哈希表 |
这种分类与其说是严格的学术分类,不如说是帮助初学者定方向的地图。实际结构会互相重叠。比如 Python 字典从使用角度看是基于键的映射(mapping),从实现角度看又和哈希有关。图也可以通过组合字典和列表来做简单表示。
因此,在本节里可以这样接受这些传统数据结构名称。
- 数组和列表让你想到顺序与位置。
- 栈和队列让你想到放入和取出的规则。
- 树让你想到层级。
- 图让你想到关系。
- 哈希表和字典让你想到按键查找。
这张地图会延伸到 P2-9.2、P2-9.3、P2-9.4。P2-9.2 会广泛比较数组、表、树、图,P2-9.3 会从关系表示角度单独看图,P2-9.4 会把传统数据结构名称作为补充学习再慢慢整理。
数据结构要和操作一起看¶
承载数据的形状,会和处理这些数据的操作(operation)连在一起。
例如,如果你想按顺序查看所有分数,列表就是自然选择。
问题场景:你想看从头到尾按顺序检查全部分数的操作。 输入(input):分数列表 scores。 期望输出(output):每个分数各打印一行。 要确认的概念:以遍历为中心的工作,与列表结构很匹配。
但如果你需要按姓名找到某个学生的分数,字典会更直接。
问题场景:你想看按姓名直接找到某个学生分数的操作。 输入(input):以姓名为键的字典 score_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:以搜索为中心的工作,用基于键的结构更能直接显露意图。
这两种结构都能装分数,但常做的操作不同。
| 常做的事情 | 第一反应应想到的结构 |
|---|---|
| 按顺序处理全部内容 | 列表(list) |
| 按姓名或 ID 查找 | 字典(dictionary) |
| 去重或检查是否包含 | 集合(set) |
| 表示父子关系 | 树(tree) |
| 表示多个对象之间的连接 | 图(graph) |
学习数据结构时,与其先问 这个结构叫什么名字?,不如先问 这个结构是为了让哪种操作更容易?
区分抽象数据类型与实现¶
学习数据结构时,你会遇到栈、队列、字典、集合这些名称。这里有一个很容易混淆的区分。
抽象数据类型(abstract data type, ADT)描述的是:允许哪些值和哪些操作。
实现(implementation)描述的是:这个概念在真实内存和代码里究竟怎么做出来。
例如,栈(stack)可以被解释为“最后放进去的先拿出来”的结构。这是一条行为规则。
push: 放入一个值pop: 取出最近放入的值- 最后放入的值会最先出来
但这个栈在内部既可以用列表实现,也可以用链表实现。同一个抽象数据类型,可以有多种实现方式。
这个区分在阅读 Python 时也很重要。
| 视角 | 问题 | 例子 |
|---|---|---|
| 抽象数据类型(ADT) | 它承诺了什么行为? | 栈会先取出最后放入的值 |
| 实现(implementation) | 它实际是怎么存的? | 可以用列表实现,也可以用链式结构实现 |
| Python 使用视角 | 它通过什么对象和方法提供? | list.append()、list.pop() |
本节先看使用视角,而不是实现细节。等到后面进入性能或算法时,我们会再次看到为什么实现方式重要。
同一份数据也会因为目的不同而改变结构¶
下面展示的是同一份学生数据用三种不同方式表示的例子。
当你想按顺序处理时¶
问题场景:你想看一种按顺序逐个处理所有学生的结构。 输入(input):包含学生字典的列表 students。 期望输出(output):按顺序打印每个学生的姓名和分数。 要确认的概念:当需要按顺序处理同类记录时,“列表里放字典”是很自然的结构。
这种结构适合把所有学生一个个处理。
当你想按姓名直接查找时¶
问题场景:你想看一种仅凭一个学生姓名就能直接找到分数的结构。 输入(input):按姓名组织的学生分数字典 student_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:如果姓名查询是中心任务,把外层结构设成字典更容易阅读。
这种结构适合按姓名找到某个具体学生。
当你想表示关系时¶
问题场景:你想看一种表示学生之间朋友关系这类连接的结构。 输入(input):以学生姓名为键、朋友列表为值的 friends。 期望输出(output):与 "Kim" 相连的朋友列表。 要确认的概念:如果关系表示是中心任务,就需要先有图的直觉。
这种结构表达的是“谁和谁相连”。虽然我们还没有深入学习图(graph),但 对象与对象之间的连接 这种感觉已经出现了。
即使是同样的“人”的数据,只要目的变了,结构也会变。这就是为什么需要数据结构。
为什么 AI 实践需要数据结构直觉¶
在 AI 实践里,即使你没有显式学习数据结构,也会不断遇到多种结构。
| AI 实践场景 | 经常出现的结构 | 阅读视角 |
|---|---|---|
| 多个句子输入 | 列表(list) | 逐句处理 |
| 连接标签编号和名称 | 字典(dictionary) | 按键找标签名 |
| 检查重复 token | 集合(set) | 判断是否包含 |
| 表格形式数据 | 表(table)、DataFrame | 按行和列访问 |
| 句子内部的 token 流 | 序列(sequence) | 按顺序处理 |
| 文档和文档之间的连接 | 图(graph) | 沿关系移动 |
本节重要的不是把所有结构都背下来,而是看数据到底提出了什么问题。
- 顺序重要吗?
- 需要按名字查找吗?
- 需要去重吗?
- 有层级吗?
- 需要沿着关系追踪吗?
- 需要快速搜索吗?
问题一变,数据结构也会跟着变。
选择数据结构不只是性能问题¶
一学数据结构,性能讨论就会跟着出现。搜索是否快、添加是否快、会占用多少内存,这些问题都很重要。
但这里不只看性能。我们也一起看可读性、出错可能性,以及数据本身的含义。
例如,在小数据里,扫描列表也可能已经足够。
问题场景:你想看到,当数据规模不大时,通过遍历列表找到需要的学生也是可行的。 输入(input):学生字典列表 students。 期望输出(output):姓名为 "Kim" 的学生分数。 要确认的概念:数据结构选择不仅要看性能,也要一起考虑数据规模和可读性。
如果数据变大,而且你经常需要按姓名查找,那么字典会更自然。
问题场景:你想看一个在“按姓名组织”的结构里更直接完成同样查询的例子。 输入(input):以学生姓名为键的 student_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:如果结构本身就显露了常做操作,代码意图也会更清楚。
这种差别不只是快慢问题。第二段代码让结构本身就显露出 按姓名查找 这个目的。
好的数据结构也会显露代码意图。
通过案例来看¶
案例 1. 明明是同一份学生数据,为什么还要重新选结构¶
假设一位学习者想用学生分数数据做三件事:计算整体平均分、立刻找到某个名字对应的分数、以及把朋友关系也一起看进去。
人一开始可能会想:反正是同一份数据,能不能都塞进一个结构里? 但计算平均分更适合按顺序看数字,按名字查找更适合按键搜索,朋友关系则更适合沿着连接来表达。
这就是为什么本节把数据结构解释成 组织数据的方法。选择结构不是在选语法偏好,而是在决定“要让哪类问题更容易回答”。
可检查的结果是:即使来自同一份源数据,只要任务变了,表示方式也会变。如果用于平均计算的分数列表、按姓名组织的分数字典、以及朋友关系图分别都更容易阅读,那就说明数据结构的选择已经影响了计算方式。
检查清单¶
- 能把数据结构解释成组织数据的方法。
- 能说明在传统数据结构导论里,数组、链表、栈、队列、树、图、哈希表分别代表什么问题。
- 能在入门层面解释线性结构与非线性结构的区别。
- 能说明数据结构会和搜索、添加、删除、遍历等操作连在一起。
- 能说明同一份数据会因为顺序、键、关系不同而以不同结构表示。
- 能在入门层面区分抽象数据类型(ADT)与实现。
- 能说明在 AI 实践中,列表、字典、集合、表、图是为了回答不同问题而使用的结构。
- 能把数据结构选择和“不是把数据放在哪里,而是让它回答什么问题”联系起来。
来源与参考资料¶
- Paul E. Black, data structure, Dictionary of Algorithms and Data Structures, NIST,确认日期:2026-07-20。用于确认把 data structure 说明为组织数据方式的定义。
- Paul E. Black, abstract data type, Dictionary of Algorithms and Data Structures, NIST,确认日期:2026-07-20。作为把 abstract data type 区分为偏向行为而非实现的框架依据。
- Python Software Foundation, Data Structures, Python 3.14.6 documentation,确认日期:2026-07-20。用于把 Python list 与 dictionary 示例连接到数据结构选择说明。