Py算法与数据结构

11 什么是排序?

排序规则、记录关联、稳定性与成本

1. 排序到底改变了什么?

排序把记录按照一个或多个键重新排列。记录中的其他字段必须跟着键一起移动;不是把分数排好后,再随意配回姓名。

升序意味着相邻键满足 key(a[i]) <= key(a[i+1]);降序反过来。允许重复值,排序结果不要求严格递增。

2. 记录、键和比较规则

学生记录可以包含姓名、分数、班级。以分数为键排序,不会改变姓名与分数的对应关系。多关键字使用元组:先比较第一项,相同时再比较第二项。

3. 用 Python 排序

students = [
    {"name": "小林", "score": 90, "class": 2},
    {"name": "小周", "score": 80, "class": 1},
    {"name": "小陈", "score": 90, "class": 1},
]
by_score = sorted(students, key=lambda s: s["score"])
by_score_desc = sorted(students, key=lambda s: s["score"], reverse=True)
by_class_score = sorted(students, key=lambda s: (s["class"], -s["score"]))
print([s["name"] for s in by_score])  # 小周、小林、小陈

sorted 返回新列表,原列表不变。list.sort 原地修改列表,返回 None;不要写 a = a.sort()。两者都支持 key、reverse,并保证稳定性。

4. 内部排序与外部排序

数据及算法所需的工作空间能放进内存时,可进行内部排序;超过内存容量时,需要把数据分块处理,并通过外部文件保存有序段。外排重点包括块大小、缓冲区和读写轮数。不要把原书旧硬盘的毫秒数当作现代设备的固定指标。

5. 比较排序与非比较排序

比较排序依靠键的大小比较。对任意互异键排序,比较模型的最坏情况及平均比较次数下界为 Ω(n log n)。这不是“每一个输入都至少要比较 n log n 次”。

计数排序等利用有限整数范围,时间通常写为 O(n + K),K 为键范围。它没有违反比较模型下界,因为使用了额外条件。本套教材以比较排序为主。计数、桶式方法和基数排序各有键类型、范围或分布方面的条件;不能把“非比较”直接理解为任意输入都线性。

6. 如何分析排序成本?

明确 n 是记录数量,再统计键比较、交换、元素写入和额外空间。字符串键比较还可能依赖字符串长度。一次交换不等于一次写入;不同实现必须统一口径才能比较。大 O 不是实际秒数,小数据上的常数也很重要。Python 列表存放对象引用,交换通常移动引用,不是把记录的所有字段逐字节复制;原书的“指针数组排序”思想可对应到这种间接访问。

7. 稳定性:相等键保留原顺序

5A 和 5B 的键都为 5,标签 A、B 只是区分记录身份。稳定排序应保留它们原来的相对先后。稳定不等于输出有序;不稳定算法某一次也可能碰巧保留顺序。

稳定性适合多次按不同字段排序:先按次要键,再稳定地按主要键排序。也可以把原始位置作为次要键,建立 (key, original_index) 的全序规则。

8. 装饰、排序、还原

records = [(5, "A"), (2, "X"), (5, "B")]
decorated = [(row[0], i, row) for i, row in enumerate(records)]
result = [row for _, _, row in sorted(decorated)]
print(result)  # [(2, "X"), (5, "A"), (5, "B")]

原位置参与比较后,即使底层算法没有稳定性保证,也可得到按原始顺序打破平局的结果;额外装饰数据占 O(n) 空间。

9. 选择算法前先问哪些问题?

数据规模、是否近乎有序、稳定性、更新频率、键比较成本、额外内存,以及数据是否需要从文件读取,都影响选择。不要沿用原文“几十、1000”等硬阈值;阈值应由实际环境测量。实际 Python 任务通常先考虑内置排序,而不是因为学过快排就重写它。

算法 平均时间 最坏时间 稳定性(常规实现)
冒泡、插入 O(n²) O(n²) 稳定
交换式选择 O(n²) O(n²) 不稳定
希尔 取决于增量序列 折半序列可为 O(n²) 不稳定
快速 O(n log n) O(n²) 不稳定
归并 O(n log n) O(n log n) 稳定(相等取左)
堆排序 O(n log n) O(n log n) 不稳定

堆排序在原书中仅作分类说明,本套不展开实现。优化冒泡和插入的最好情况可达 O(n),表格中的平均/最坏不能代替最好情况。

10. 本套教材的约定与校正

数组下标从 0 开始,演示标签不参与键比较。原文的 OCR 混淆了 O(n)、O(n²) 等公式;本套统一纠正。常规选择排序、希尔排序和原地快排不稳定;稳定归并排序并不“慢到必须放弃稳定性”。