本讲定位:★ 高频。七年真题统计(见
cspj-exam-analysis-2019-2025.md):排序查找类选择题约每年 1~2 题(稳定性 2022、逆序对 = 冒泡交换次数 2025、找最大的比较下界 2021、二分次数 2019/2024);更要紧的是二分查找连续三年进完善程序(2021 矩形计数、2022 求平方根、2023 找缺失数),边界收缩写法是挖空重灾区。本讲是”知识 + 能力”双属性:前半部分手算(量级排序、稳定性表、模拟排序过程),后半部分读写代码(二分模板必须默写级掌握)。从本讲起,课程重心开始向”读程序、写程序”倾斜。前置知识:第 02 讲的 $2^k$ 数感(二分次数);第 06 讲的完全二叉树(堆排序的”堆”、二分的决策树);第 12 讲的递归(归并/快排的递归结构,读懂即可)。
适合对象:CSP-J 初赛。标注 ⭐ 的小节为进阶内容,第一遍学习可以跳过。
$O$ 记号刻画的是运行时间随 $n$ 增长的速度,忽略常数与低阶项:$3n^2 + 5n + 7$ 就是 $O(n^2)$。初赛必背的量级链(从快到慢):
$$ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(n^3) < O(2^n) < O(n!) $$
看循环数量级的基本功(第 09 讲会深化成完整方法论):
| 代码形态 | 复杂度 | 记忆点 |
|---|---|---|
| 单层循环跑到 $n$ | $O(n)$ | |
| 两层嵌套各跑到 $n$ | $O(n^2)$ | 内层跑到 $i$ 也是 $O(n^2)$(求和 $\frac{n(n-1)}{2}$) |
i *= 2 或每轮折半 |
$O(\log n)$ | 翻倍/折半 = 对数 |
| 外层 $n$、内层折半 | $O(n \log n)$ | 归并、快排、堆排的量级 |
由数据范围反推可行算法(完善程序选思路时的”作弊表”,按一秒约 $10^8$ 次基本运算估):
| $n$ 的规模 | 可接受的复杂度 | 对应算法举例 |
|---|---|---|
| $n \le 20$ | $O(2^n)$ | 枚举子集、搜索 |
| $n \le 500$ | $O(n^3)$ | 三重循环 |
| $n \le 5000$ | $O(n^2)$ | 冒泡/插入/选择排序、双重循环 |
| $n \le 10^5$ | $O(n \log n)$ | 归并/快排、sort、二分 |
| $n \le 10^7$ | $O(n)$ | 一遍扫描、计数排序 |
例 1:$n = 10^5$ 的数组用冒泡排序要约 $10^{10}$ 次操作——超时百倍;换 $O(n \log n)$ 的 sort 约 $1.7 \times 10^6$,绰绰有余。“这段程序对 $n = 10^5$ 能否在时限内出解”就按这两张表判断。
稳定性:排序后相等元素的相对次序不变,则称稳定。总表必背(★ 标出真题直接考过的格子):
| 排序 | 平均 | 最坏 | 最好 | 稳定性 | 一句话特征 |
|---|---|---|---|---|---|
| 冒泡 | $O(n^2)$ | $O(n^2)$ | $O(n)$★(带 FLAG) | 稳定 | 相邻交换,交换次数 = 逆序对数★ |
| 插入 | $O(n^2)$ | $O(n^2)$ | $O(n)$ | 稳定 | 新牌插进手里的有序牌;近乎有序时飞快 |
| 选择 | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | 不稳定★ | 每轮选最小放前面;比较次数固定 $\frac{n(n-1)}{2}$ |
| 归并 | $O(n \log n)$ | $O(n \log n)$ | $O(n \log n)$ | 稳定 | 分两半各自排好再合并;需 $O(n)$ 辅助数组 |
| 快排 | $O(n \log n)$ | $O(n^2)$★ | $O(n \log n)$ | 不稳定 | 选基准分两侧;已有序 + 取端点基准 = 最坏 |
| 堆排 | $O(n \log n)$ | $O(n \log n)$ | $O(n \log n)$ | 不稳定 | 用完全二叉树(第 06 讲编号)维护最值 |
| 计数 | $O(n + w)$ | $O(n + w)$ | $O(n + w)$ | 稳定★ | 不比较、按值开桶;$w$ 是值域大小 |
| 基数 | $O(d(n + w))$ | 同左 | 同左 | 稳定 | 按低位到高位逐位计数排序,$d$ 是位数 |
三个必考记忆点:
⭐ 比较类排序的极限是 $O(n \log n)$(决策树深度),计数/基数能更快是因为它们不做比较、直接按值分桶——这也是”计数排序不属于比较排序”这类判断题的依据。