⌨️ 第三章 数值和数据的处理方法
📄 一句话概括

100 个学生的成绩,起 100 个变量名会疯——数组把【同类型的很多个】装进一条编号连续的走廊,一个名字加一个下标就能访问任何一个;下标从 0 开始是本节的终身必修。

📝 本节和前面几节的关系

3-4 的变量是单间房,数组是整层楼。回收树莓派课 6-6(Python 列表与字符串)与 C++ 课第七章(数组)——C 的数组是【静态数组】的原教旨形态,Python 列表是【动态数组】的舒适版。

一、数组:同类型数据的编号走廊

数组三特征:

  1. 同类型:一条走廊全住 int(或全住别的同一种类型);
  2. 连续内存:一个个房间紧挨着——这是它快(按下标一步到位)的物理基础;
  3. 按下标访问:scores[3] 就是第四间房(下标从 0 数起)。

下标为什么从 0 开始:scores[3] 的真实含义是【从开头偏移 3 个元素的位置】——开头 + 偏移,偏移从 0 数。这不是怪癖,是【下标 = 距离开头的步数】的直接后果。

二、静态数组 vs 动态数组

静态数组 动态数组
大小何时定 编译期写死(C:int a[100]) 运行时随加随长
内存 一块连续空间,不能变 后台管着一块可扩容的空间
代价 写死太短会溢、太长浪费 扩容时要搬家(有瞬间开销)
代表 C/C++ 原生数组 Python list、C++ vector、Java ArrayList

扩容的真实机制:动态数组满了不是【原地加盖】,是另找一块约 1.5~2 倍大的新地、整体搬过去——所以【偶尔一下变慢】是它的固有性格。

三、多维数组:走廊上叠走廊

一维是线(一行成绩),二维是表格(30 个学生 x 5 科):table[学生][科目]。内存里其实仍是拉直的一条线——行优先铺开,[2][4] 的意思是【跳过前两行、再走 4 步】。三维以上同理(一摞表格),日常二维最常见。

四、动手 Demo:走廊巡视

scores = [88, 92, 75, 60, 95]      # Python 动态数组

print(scores[0], scores[-1])       # 88 95   首与尾(-1 是倒数第一)
print(len(scores))                 # 5
print(sum(scores) / len(scores))   # 82.0

scores[3] = 61                     # 按下标改第四间房
print(scores)                      # [88, 92, 75, 61, 95]

看到什么算成功:88 95、5、82.0、[88, 92, 75, 61, 95]。

读结果:scores[3] 是 60 不是 75——下标 0/1/2/3 对应第 1/2/3/4 个元素,【第几个】和【下标几】永远差一。平均分 82.0 沿用 3-3 的真除。

五、30 秒实验

跑 a = [0] * 5,打印得 [0, 0, 0, 0, 0];再跑 a[5] = 1——当场 IndexError: list index out of range。下标最大只到 4:从 0 开始的走廊,5 间房的最后门牌是 4。越界是数组的第一大事故源。

六、常见误区

  1. 【第 5 个元素写作 scores[5]】——错。是 scores[4];scores[5] 是第六间(不存在),越界。
  2. 【数组和列表是两种没关系的类型】——基本对但精神相通:C 数组管内存的方式最【裸】(定长、自己看着别越界),Python list 是管理完善的动态数组——学的是同一条走廊。
  3. 【二维数组就是【一维数组的数组】所以随便长】——C 里错:静态二维数组的每一行必须等长(连续内存摊平的要求);Python 里才宽松(列表套列表可以参差)。
自测三问(点开对答案) 1. **为什么数组下标从 0 开始?** 答:下标本质是【距开头的偏移量】,偏移自然从 0 数起——scores[3] 就是开头往后走 3 步。 2. **静态与动态数组的核心差异?** 答:大小定于编译期且不可变(C 数组)vs 运行时可扩容(背后是整体搬家式的重新分配)。 3. **一个 4 行 6 列的二维数组共有几个元素、最后一个的下标?** 答:24 个;最后一个是 table[3][5]——行列都从 0 数,各减一。

相关笔记