跳转至

P2-9.1 为什么需要数据结构

Section ID: P2-9.1 Version: v2026.07.20

在 P2-8 中,我们已经看过 Python 的值、列表、字典、循环、函数和类。现在我们后退一步,把问题换掉。

数据应该用什么形状来装?

这个问题就是数据结构的出发点。数据结构不只是语法名称。数据如何组织、哪些操作会被频繁执行,会一起改变代码的形状和计算的方式。

这里说明 data structureabstract data typelinear structurenon-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。 要确认的概念:列表是适合按顺序处理值的基本数据结构。

# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
scores = [82, 75, 91]

这种结构适合按顺序处理分数。

问题场景:当你想按学生姓名直接找到分数时,想看到为什么需要另一种结构。 输入(input):以姓名为键、分数为值的 score_by_name。 期望输出(output):按姓名组织的分数字典映射。 要确认的概念:即使是同样的数据,如果按姓名查找更重要,字典会更自然。

1
2
3
4
5
6
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
score_by_name = {
    "Kim": 82,
    "Lee": 75,
    "Park": 91,
}

这种结构适合按姓名查找分数。

即使是同样的数据,适合的结构也会因为“按顺序看”“按姓名查找”“沿着关系追踪”而不同。

核心判断标准:为什么需要数据结构

  • 能把数据结构解释成组织数据的方法。
  • 能在入门层面解释线性结构与非线性结构的区别。
  • 能说明数据结构会和搜索、添加、删除、遍历等操作连在一起。
  • 能说明同一份数据会因目的不同而被表示成列表、字典、表、图等不同形式。
  • 能在入门层面区分抽象数据类型与具体实现。
  • 能说明在 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):每个分数各打印一行。 要确认的概念:以遍历为中心的工作,与列表结构很匹配。

1
2
3
4
5
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
scores = [82, 75, 91]

for score in scores:
    print(score)

但如果你需要按姓名找到某个学生的分数,字典会更直接。

问题场景:你想看按姓名直接找到某个学生分数的操作。 输入(input):以姓名为键的字典 score_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:以搜索为中心的工作,用基于键的结构更能直接显露意图。

1
2
3
4
5
6
7
8
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
score_by_name = {
    "Kim": 82,
    "Lee": 75,
    "Park": 91,
}

print(score_by_name["Kim"])

这两种结构都能装分数,但常做的操作不同。

常做的事情 第一反应应想到的结构
按顺序处理全部内容 列表(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):按顺序打印每个学生的姓名和分数。 要确认的概念:当需要按顺序处理同类记录时,“列表里放字典”是很自然的结构。

1
2
3
4
5
6
7
8
9
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
students = [
    {"name": "Kim", "score": 82},
    {"name": "Lee", "score": 75},
    {"name": "Park", "score": 91},
]

for student in students:
    print(student["name"], student["score"])

这种结构适合把所有学生一个个处理。

当你想按姓名直接查找时

问题场景:你想看一种仅凭一个学生姓名就能直接找到分数的结构。 输入(input):按姓名组织的学生分数字典 student_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:如果姓名查询是中心任务,把外层结构设成字典更容易阅读。

1
2
3
4
5
6
7
8
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
student_by_name = {
    "Kim": {"score": 82},
    "Lee": {"score": 75},
    "Park": {"score": 91},
}

print(student_by_name["Kim"]["score"])

这种结构适合按姓名找到某个具体学生。

当你想表示关系时

问题场景:你想看一种表示学生之间朋友关系这类连接的结构。 输入(input):以学生姓名为键、朋友列表为值的 friends。 期望输出(output):与 "Kim" 相连的朋友列表。 要确认的概念:如果关系表示是中心任务,就需要先有图的直觉。

1
2
3
4
5
6
7
8
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
friends = {
    "Kim": ["Lee", "Park"],
    "Lee": ["Kim"],
    "Park": ["Kim"],
}

print(friends["Kim"])

这种结构表达的是“谁和谁相连”。虽然我们还没有深入学习图(graph),但 对象与对象之间的连接 这种感觉已经出现了。

即使是同样的“人”的数据,只要目的变了,结构也会变。这就是为什么需要数据结构。

为什么 AI 实践需要数据结构直觉

在 AI 实践里,即使你没有显式学习数据结构,也会不断遇到多种结构。

AI 实践场景 经常出现的结构 阅读视角
多个句子输入 列表(list) 逐句处理
连接标签编号和名称 字典(dictionary) 按键找标签名
检查重复 token 集合(set) 判断是否包含
表格形式数据 表(table)、DataFrame 按行和列访问
句子内部的 token 流 序列(sequence) 按顺序处理
文档和文档之间的连接 图(graph) 沿关系移动

本节重要的不是把所有结构都背下来,而是看数据到底提出了什么问题。

  • 顺序重要吗?
  • 需要按名字查找吗?
  • 需要去重吗?
  • 有层级吗?
  • 需要沿着关系追踪吗?
  • 需要快速搜索吗?

问题一变,数据结构也会跟着变。

选择数据结构不只是性能问题

一学数据结构,性能讨论就会跟着出现。搜索是否快、添加是否快、会占用多少内存,这些问题都很重要。

但这里不只看性能。我们也一起看可读性、出错可能性,以及数据本身的含义。

例如,在小数据里,扫描列表也可能已经足够。

问题场景:你想看到,当数据规模不大时,通过遍历列表找到需要的学生也是可行的。 输入(input):学生字典列表 students。 期望输出(output):姓名为 "Kim" 的学生分数。 要确认的概念:数据结构选择不仅要看性能,也要一起考虑数据规模和可读性。

1
2
3
4
5
6
7
8
9
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
students = [
    {"name": "Kim", "score": 82},
    {"name": "Lee", "score": 75},
]

for student in students:
    if student["name"] == "Kim":
        print(student["score"])

如果数据变大,而且你经常需要按姓名查找,那么字典会更自然。

问题场景:你想看一个在“按姓名组织”的结构里更直接完成同样查询的例子。 输入(input):以学生姓名为键的 student_by_name。 期望输出(output):"Kim" 的分数 82。 要确认的概念:如果结构本身就显露了常做操作,代码意图也会更清楚。

1
2
3
4
5
6
7
# 这个例子用来确认列表、字典和嵌套结构如何保存并查找数据。
student_by_name = {
    "Kim": {"score": 82},
    "Lee": {"score": 75},
}

print(student_by_name["Kim"]["score"])

这种差别不只是快慢问题。第二段代码让结构本身就显露出 按姓名查找 这个目的。

好的数据结构也会显露代码意图。

通过案例来看

案例 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 示例连接到数据结构选择说明。