数组区间
每次只处理一个闭区间 [left, right]。
同一组 8 个数,两条不同路线:快排把工作放在“分”,归并把工作放在“合”。拖慢课堂的不是递归,而是没看见递归中维护的信息。
先看对象、维护量与易卡点,再进入动画。
每次只处理一个闭区间 [left, right]。
拆成同类、规模更小的子问题,直到到达出口。
快排维护 pivot / i / j;归并维护两个队首与临时数组。
不保存子区间经历过的所有比较,只保留组合答案所需的信息。
会背递归代码,却说不清快排为何不用合并、归并为何只看两个队首。
不要先背代码,先判断主要工作发生在哪一步。
分区结束后,左侧都不大于 pivot,右侧都不小于 pivot。左右内部排好,整个区间自然有序。
切半本身不改变元素顺序。真正产生当前区间答案的是“两个有序队首竞争下一个位置”。
切换模式,逐步播放或自动播放;每一步都显示算法真正维护的状态。
[5, 3, 8, 4, 9, 7, 1, 6]关键:pivot 保存的是数值 4 的副本,不是固定位置。黄色框会跟随元素 4 从下标 3 移到下标 2。
树状区域显示当前已完成的递归层;下方显示最后一次合并时两个队首与临时数组。
区间越来越小,但同一层所有区间的长度加起来仍然是 n。
递归树始终约有 log n 层,所以最坏时间也是 O(n log n)。
若每次大致分半,平均为 O(n log n);若长期只缩小一点,最坏会形成 n 层,退化为 O(n²)。
代码不是另一个世界:每个变量都对应动画里看得见的状态。
#include <bits/stdc++.h>
using namespace std;
void quickSort(vector<int>& a, int left, int right) {
if (left >= right) return;
int pivot = a[left + (right - left) / 2];
int i = left, j = right;
while (i <= j) {
while (a[i] < pivot) ++i;
while (a[j] > pivot) --j;
if (i <= j) {
swap(a[i], a[j]);
++i;
--j;
}
}
if (left < j) quickSort(a, left, j);
if (i < right) quickSort(a, i, right);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int& x : a) cin >> x;
quickSort(a, 0, n - 1);
for (int x : a) cout << x << ' ';
cout << '\n';
return 0;
}
#include <bits/stdc++.h>
using namespace std;
void mergeSort(vector<int>& a, vector<int>& temp,
int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSort(a, temp, left, mid);
mergeSort(a, temp, mid + 1, right);
int i = left, j = mid + 1, k = left;
while (i <= mid && j <= right) {
if (a[i] <= a[j]) temp[k++] = a[i++];
else temp[k++] = a[j++];
}
while (i <= mid) temp[k++] = a[i++];
while (j <= right) temp[k++] = a[j++];
for (int p = left; p <= right; ++p) {
a[p] = temp[p];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n), temp(n);
for (int& x : a) cin >> x;
mergeSort(a, temp, 0, n - 1);
for (int x : a) cout << x << ' ';
cout << '\n';
return 0;
}
left >= right长度为 0 或 1 的区间天然有序,递归在这里停止。
pivot / i / j动画中的黄色基准、蓝色左指针和橙色右指针直接映射到这三个变量。
i / j / k / temp两个队首竞争,胜者写入 temp[k],最后再复制回原数组。
点击选项立即获得与当前模型相关的反馈。
请选择一个答案。
请选择一个答案。
请选择一个答案。
从完整排序出发,逐步减少工作或增加维护信息。
完整实现快排或归并,练习出口、分区边界与写回。
打开题目 Markdown →在归并时增加一个计数:一次加入左侧剩余元素个数。
打开题目 Markdown →利用分区位置,只继续处理答案所在的一侧。
打开题目 Markdown →大问题拆成同类小问题,只保留组合答案所需的信息,并确保每层总工作量可控。
回到 Markdown 讲义 →先只播放快排到“分区完成”,暂停并追问:哪些关系已经确定,哪些仍未知?再切换归并,只播放到两个四元素有序区间,让学生预测下一次进入临时数组的元素。
复杂度动画不要直接给结论。每展开一层,先让学生把该层所有小块长度相加,再说出“每层 n、约 log n 层”。