题目描述
给定你一个长度为n的整数数列。
请你使用快速排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在1~109范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
题目分析
本题是一道基础算法的模板题,考察的就是快速排序。
快速排序是一种基于分治的算法,基本步骤为:
-
确定分界点 pivot
在区间[left, right ]内选择分界点的方式一般有
①num[left]
②num[right]
③ num[left+right>>1] (也就是取中间元素)
④num[rand()%len] (随机取点)
本题中选用方式①和②作为pivot会被卡掉 -
将大于等于pivot的元素移到右边,小于等于pivot的元素移到左边(但是pivot不一定归位)。
调整的方式其实是一种双指针算法
每次左指针i寻找≥pivot的元素,右指针j寻找≤pivot的元素
if i<j则交换num[i], num[j]
当i ≥ j时说明已经调整完毕 -
递归处理由pivot划分的左右区间。
递归终止条件:区间内只有一个元素即left ≥ right时结束。
算法分析
时间复杂度:平均情况O(nlog2n), 最坏情况O(n2)
算法实现
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5+10;
int num[N];
void quick_sort(int l, int r) {
if(l >= r) return;//只有一个元素或无元素递归结束
int pivot = num[l+r>>1];//取中间元素作为枢轴
//利用双指针算法划分区间
int i = l-1, j = r+1;
while(i < j) {
while(num[++i] < pivot);
while(num[--j] > pivot);
if(i < j) swap(num[i], num[j]);
}
//递归排序子区间
quick_sort(l, j);
quick_sort(j+1, r);
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%d", &num[i]);
quick_sort(0, n-1);
for(int i = 0; i < n; ++i) printf("%d ", num[i]);
puts("");
return 0;
}