快速排序

812 字
4 分钟
快速排序

快速排序#

快速排序是分治思想里很经典的一类排序。它的核心不是“直接把整个数组排好”,而是先选一个分界值,把数组分成两边:

  • 左边的数都不大于分界值。
  • 右边的数都不小于分界值。
  • 然后递归处理左右两段。

这样每一层都把问题拆小,直到区间里只剩一个数,整个数组自然就有序了。

1、适合解决什么问题#

给定一个数组,要求从小到大排序:

5 3 8 4 2

排序后得到:

2 3 4 5 8

快速排序通常用于普通数组排序,平均时间复杂度是 O(n log n),代码也比较短。

2、快速排序的基本步骤#

1. 选择一个分界值 x
2. 用两个指针 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);

一个从左往右,一个从右往左,分别找需要交换的位置。

总结#

快速排序可以记成:

选分界值 -> 双指针划分 -> 递归左右两边

真正难点不是递归,而是理解双指针为什么能把小数放左边、大数放右边。把这一点想清楚,模板就比较好背了。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

快速排序
https://blog.tjcheng.cn/posts/migrated/old-73/
作者
TengJinCheng
发布于
2025-09-27
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
TengJinCheng
Hello, I'm Teng.
公告
欢迎来到TengJinCheng工作铺!
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
分类
标签
站点统计
文章
157
分类
7
标签
114
总字数
109,939
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.4
文章许可
CC BY-NC-SA 4.0

文章目录