一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
题目
给定你一个长度为 n 的整数数列。
请你使用快速排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n个整数(所有整数均在 1∼10^9 范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
时间复杂度
O(nlogn)
主要思想
基于分治
主要步骤
1. 随便取一个值作为分界点,一般有下面4种分界点
1. 取左边的值作为边界q[l]
1. 取中间的值作为边界q[(l + r) / 2]
1. 取右边的值作为边界q[r]
1. 随便一个值作为边界
2. 调整区间(难点):以自己选取的x作为分界点,划分成两个区间,使得第一个区间的数都小于等于x,第二个区间的数都大于等于x
2. 递归处理左右两段
第二步的做法有以下两种思路
1. 暴力做法
- 额外用到两个数组
2.优美一点的做法(也就是快排模板)
a. 用两个指针,i指向左边,j指向右边 b. 先移动i指针,直到i移动到大于等于x的值的时候就要停下来,接着移动j指针,当j指针移动小于等于x的数的时候就停下来,然后i跟j所指向的值swap一下,无论什么时候i左边的值都是小于等于x的,j右边的值都是大于等于x的 c. 交换完之后,两个指针要往中间移动一位
模板
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return; // 如果左边大于右边的话我们就不用排序了
int x = q[l + r >> 1], i = l - 1, 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;
}
边界问题
1. 当x = q[l]的时候,不能取到quick_sort(q, l, i - 1); quick_sort(q, i, r); ,因为会出现死循环,例子:1,2
1. 当x = q[r]的时候,不能取quick_sort(q, l, j);quick_sort(q, j + 1, r); ,因为会出现死循环,例子:1,2
这篇博客很牛逼,有空的话可以看一下: AcWing 785. 快速排序算法的证明与边界分析 - AcWing
快排什么时候会用到
1. 面试的时候会用到,手写快排 1. 其他时候基本不会用到