目标:理解快速排序分区逻辑:左侧不大于 pivot,右侧不小于 pivot(本页使用 Hoare 双指针)。
public static void quicksort (int[] a, int lo, int hi) {
if ( hi <= lo ) return;
int p = partition(a, lo, hi);
quicksort(a, lo, p-1);
quicksort(a, p+1, hi);
}
把快速排序理解成“反复做同一件事”:先把一段数字分成左右两边,再分别处理左右两边。
下面这段解释是对第二屏代码的逐行说明,先看清“它在干什么”,再看“为什么这样做”。
quicksort 的参数是什么意思?(这是最容易忽略的关键点)
partition 的参数是什么意思?(它只处理 a 的一小段)
重要提示:这两个函数处理的范围都是 lo 到 hi 的闭区间,也就是 lo 和 hi 都要算进去。
partition 的作用是什么?它只做三件事:选 pivot、让左右分区、返回 pivot 的位置 p。它不会一次就把整段排好,只是把问题拆成更小的左右两段。
quicksort 的作用是什么?它负责“不断对左右两段重复分区”,直到每段都很短(0 或 1 个元素),这时整个数组就有序了。
一句话记忆:选 pivot → 分左右 → pivot 归位 → 递归左右,直到区间足够小。
本次是 partition(0, 15),基准值 pivot 为 49。每一帧都显示完整数组,并标出 i 和 j 的当前位置。
阅读顺序:先看 i/j 指针位置,再看数组变化;i < j 时交换,i >= j 时结束扫描。
递归树(文字版)
quicksort(0,15) -> p=11 ├─ quicksort(0,10) -> p=0 │ ├─ quicksort(0,-1) 结束 │ └─ quicksort(1,10) -> p=3 │ ├─ quicksort(1,2) -> p=1 │ │ ├─ quicksort(1,0) 结束 │ │ └─ quicksort(2,2) 结束 │ └─ quicksort(4,10) -> p=8 │ ├─ quicksort(4,7) -> p=4 │ │ ├─ quicksort(4,3) 结束 │ │ └─ quicksort(5,7) -> p=6 │ │ ├─ quicksort(5,5) 结束 │ │ └─ quicksort(7,7) 结束 │ └─ quicksort(9,10) -> p=9 │ ├─ quicksort(9,8) 结束 │ └─ quicksort(10,10) 结束 └─ quicksort(12,15) -> p=15 ├─ quicksort(12,14) -> p=12 │ ├─ quicksort(12,11) 结束 │ └─ quicksort(13,14) -> p=13 │ ├─ quicksort(13,12) 结束 │ └─ quicksort(14,14) 结束 └─ quicksort(16,15) 结束
最终有序数组
3 条记忆要点
课堂小提问(2~3 题)