快速排序
812 字
4 分钟
快速排序

快速排序
快速排序是分治思想里很经典的一类排序。它的核心不是“直接把整个数组排好”,而是先选一个分界值,把数组分成两边:
- 左边的数都不大于分界值。
- 右边的数都不小于分界值。
- 然后递归处理左右两段。
这样每一层都把问题拆小,直到区间里只剩一个数,整个数组自然就有序了。
1、适合解决什么问题
给定一个数组,要求从小到大排序:
5 3 8 4 2排序后得到:
2 3 4 5 8快速排序通常用于普通数组排序,平均时间复杂度是 O(n log n),代码也比较短。
2、快速排序的基本步骤
1. 选择一个分界值 x2. 用两个指针 i、j 从区间两端向中间走3. i 找到左边第一个 >= x 的数4. j 找到右边第一个 <= x 的数5. 如果 i < j,就交换 q[i] 和 q[j]6. 划分完成后,递归排序左区间和右区间这里最重要的是第 2 步到第 5 步,也就是“调整区间”。
3、双指针划分过程
假设数组是:
5 3 8 4 2选中间值 8 作为分界值时,左指针从左往右找不该在左边的数,右指针从右往左找不该在右边的数。
真正写模板时,我们不需要把每一步都手动模拟,只要记住这一点:
i 往右找 >= x 的数j 往左找 <= x 的数找到后交换循环结束后,j 左边是一段,j + 1 右边是一段。
4、C++ 模板
#include <bits/stdc++.h>using namespace std;
const int N = 1000010;
int n;int q[N];
void quick_sort(int q[], int l, int r) { if (l >= r) return;
int x = q[(l + r) >> 1]; int i = l - 1; int j = r + 1;
while (i < j) { do i++; while (q[i] < x); do j--; while (q[j] > x); if (i < j) swap(q[i], q[j]); }
quick_sort(q, l, j); quick_sort(q, j + 1, r);}
int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &q[i]);
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i++) printf("%d ", q[i]); return 0;}5、为什么递归区间是 [l, j] 和 [j + 1, r]
这套模板使用的是 Hoare 划分方式。循环结束时,j 是左半部分的最后一个位置,所以继续递归:
quick_sort(q, l, j);quick_sort(q, j + 1, r);不要把它随便改成 [l, i - 1] 和 [i, r],除非整套划分写法也一起换。
6、容易写错的地方
(1)l + r >> 1 最好加括号
int x = q[(l + r) >> 1];虽然位运算优先级可以记住,但加括号更清楚。
(2)递归出口不能漏
if (l >= r) return;没有出口会无限递归。
(3)两个 do-while 的方向不能反
do i++; while (q[i] < x);do j--; while (q[j] > x);一个从左往右,一个从右往左,分别找需要交换的位置。
总结
快速排序可以记成:
选分界值 -> 双指针划分 -> 递归左右两边真正难点不是递归,而是理解双指针为什么能把小数放左边、大数放右边。把这一点想清楚,模板就比较好背了。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














