Skip to content

3.10 综合练习

这一节,你能解决什么问题

学完这一节,你能够:

  1. 综合运用第三章的核心判断方法:循环不变式、复杂度分析、策略选择
  2. 审查 agent 给出的排序/查找实现,发现边界条件错误和隐藏性能问题
  3. 设计场景化的算法选择策略,而不是机械地记忆"哪个算法更好"
  4. 验证算法正确性,不只是"跑一遍看看"

问题情境

你刚学完第三章:排序与查找。

你掌握了:

  • 循环不变式证明正确性
  • 复杂度分析(最好、最坏、平均)
  • 各种排序算法的特点(插入、归并、快排、堆排序、计数排序、基数排序)
  • 二分查找及其边界条件

问题:这些知识怎么变成实际判断能力?

让我们通过练习把零散知识变成系统思维。


直观思路

练习的目的是让你"自己做一遍":

  • 基本理解:复现关键概念
  • 方法应用:把方法用到新场景
  • 错误诊断:发现别人(或 agent)的错误
  • 方案比较:权衡取舍
  • 开放设计:设计自己的解决方案

这种"主动提取"比"被动阅读"更有效。研究表明,回忆和应用的记忆留存率远高于单纯阅读。


规范定义

第三章的核心判断动作

  1. 正确性判断:用循环不变式证明,不靠"跑一遍看看"
  2. 复杂度判断:分析最好、最坏、期望情况
  3. 策略选择判断:根据场景特征选择算法
  4. 边界判断:发现边界条件错误
  5. 前提判断:验证算法前提条件是否满足

练习类型分类

类型目的认知层次
基本理解复现概念记忆、理解
方法应用迁移方法应用
错误诊断发现问题分析
方案比较权衡取舍评价
开放设计综合创造创造

这个方法是怎么想到的

为什么要有综合练习?

分散的知识点是孤岛。综合练习是桥梁。

类比:学开车,不能只懂每个操作(油门、刹车、转向),还要能在真实路况中综合运用。

第三章的每个知识点:

  • 循环不变式 → 正确性证明
  • 复杂度分析 → 性能预测
  • 排序算法特点 → 策略选择

综合练习让你在场景中调用这些知识点。

练习的设计原则

  1. 渐进难度:从基本理解到开放设计
  2. 场景真实:不考"定义是什么",而是"这个场景怎么做"
  3. 过程重于答案:提交判断过程,不只是答案

正确性分析

练习答案的验证方法

练习题的答案不只是"对/错",而是"推理是否正确"。

例子:排序策略选择

错误答案:

"应该用快排,因为快排最快。"

正确推理:

"应该用堆排序。因为场景要求最坏 Θ(n log n),快排的最坏是 Θ(n²)。虽然快排期望 Θ(n log n),但实时系统不能接受最坏情况。堆排序保证了最坏 Θ(n log n),符合需求。"

验证标准

  1. 是否识别了场景约束?
  2. 是否匹配了算法特点?
  3. 是否考虑了边界情况?

复杂度分析

练习的时间分配建议

练习类型建议时间重点
基本理解每题 5-10 分钟快速复现
方法应用每题 15-20 分钟迁移思考
错误诊断每题 10-15 分钟细心审查
方案比较每题 20-30 分钟权衡分析
开放设计每题 30-60 分钟综合设计

练习的心理陷阱

  1. 过早求答案:先尝试,再对答案
  2. 跳过推导:推导过程比结论重要
  3. 只做简单题:困难题才是提升点

什么时候不该用这个方法

练习不是目的,理解才是

不要:

  • 背答案
  • 跳过思考
  • 只做自己会的

应该:

  • 先尝试,再看提示
  • 写推理过程
  • 从错误中学习

练习之外的补充

练习覆盖了典型场景,但不是全部。实际工作中:

  1. 实际测量:复杂度分析是理论,实际要测量
  2. 混合策略:可能需要组合多种算法
  3. 工程约束:内存、并行、分布式可能改变选择

本节小结

解决了什么问题?

把第三章的零散知识点整合成判断能力。

核心方法是什么?

  • 基本理解:复现概念
  • 方法应用:迁移到新场景
  • 错误诊断:发现问题
  • 方案比较:权衡取舍
  • 开放设计:综合创造

为什么正确?

主动提取比被动阅读记忆更持久。场景化练习让知识变成能力。

适用场景?

学习第三章后,检验理解程度。发现薄弱环节。

能否自己使用?

能。关键是:

  • 不要跳过思考
  • 写推理过程
  • 从错误中学习

基本理解

练习 1:排序下界验证

用决策树模型证明:排序 3 个元素,最坏情况至少需要 5 次比较。

提示:

  • 3! = 6 种排列
  • 高度 h 的二叉树最多 2^h 个叶子
  • 为什么不是 3 次?

练习 2:循环不变式证明

用循环不变式证明 PARTITION 的正确性:

每次迭代开始时:

  • A[p..i] ≤ pivot
  • A[i+1..j-1] > pivot
  • A[r] 是 pivot

写出完整的三步证明。

练习 3:建堆过程

对数组 [3, 1, 4, 1, 5, 9, 2, 6],手动执行 BUILD-MAX-HEAP。

画出每一步的树形结构。


方法应用

练习 4:排序策略选择

给定以下场景,选择排序算法并说明理由:

场景推荐算法理由
年龄排序(0-150岁),n=10^6
URL 排序(字符串),需要稳定
嵌入式系统,内存 2KB,不能崩溃
数据流中位数计算
Top-50(n=10^6)

练习 5:哈希策略分析

缓存系统设计:

  • 1000 万条 URL
  • 每秒 10 万次查询
  • 内存 100 MB
  • 假阳性可接受,假阴性不可接受

选择哈希策略,说明理由。


错误诊断

练习 6:快排 bug

以下快排实现有什么问题?

python
def quicksort_bug(A, p, r):
    if p < r:
        q = partition(A, p, r)
        quicksort_bug(A, p, q)    # ← 这里
        quicksort_bug(A, q+1, r)

分析:递归范围是否正确?

练习 7:计数排序前提

agent 建议用计数排序优化时间戳排序。这个建议正确吗?

分析:

  • 时间戳范围
  • 数据规模 n
  • 是否满足前提条件

练习 8:二分查找边界

以下实现有什么问题?

python
def binary_bug(A, x):
    low, high = 0, len(A) - 1
    while low < high:           # ← 检查这里
        mid = (low + high) // 2  # ← 检查这里
        if A[mid] == x:
            return mid
        elif A[mid] < x:
            low = mid           # ← 检查这里
        else:
            high = mid          # ← 检查这里
    return -1

找出所有 bug。


方案比较

练习 9:排序三元悖

不存在同时满足三者的排序算法:

  1. O(n) 时间
  2. 稳定
  3. 原地

验证:列出常见排序算法的(时间、稳定、原地)三元组。

练习 10:三种 Θ(n log n) 排序对比

维度归并排序快排堆排序
最坏时间
期望时间
空间
稳定
缓存友好

填完后,给出场景匹配建议。


开放设计

练习 11:排序策略 Skill

设计一个 Skill:输入数据特征,自动选择排序策略。

python
def choose_sort_strategy(n, key_type, key_range, stable, worst_required):
    # 返回推荐算法和理由

测试用例:

  1. n=100万,整数年龄(0-150),不需要稳定
  2. n=1万,浮点得分,需要稳定
  3. n=10亿,字符串 URL,需要最坏保证

练习 12:中位数流 Skill

设计一个 Skill:实时计算数据流中位数。

  • 支持动态插入
  • 支持快速查询中位数
  • 分析复杂度

提示:两个堆(最大堆 + 最小堆)。


审查报告

练习 13:agent 输出审查

让 agent 实现一个排序系统,你审查:

  1. 是否正确选择策略?
  2. 循环不变式是否正确?
  3. 边界条件是否处理?
  4. 复杂度分析是否准确?
  5. 前提条件是否验证?

写一份审查报告。


上一节:3.9 二分查找

下一节:3.11 LLM 连接

新时代的算法课程