题目来源于ACWING
快速排序 23/11/16
习题1——快速排序
给定你一个长度为 n 的整数数列。
请你使用快速排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n
第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
#include<iostream>
using namespace std;
//多开数组长度,避免边界问题
const int N =100010;
int arr[N];
//总体思路是递归解决问题
//快排的思想:
//你有两个数组,左边数组所有元素均小于右边数组,那么你只需讲两个数组分别排好序,再合并即可
//那对于左右两边数组的该如何排序呢?
//只需递归把左右两边数组分别拆分成更小的数组即可,直到每个数组被拆分到只有一个元素则完成递归,得到结果
void quick_sort(int l,int r){
if(l>=r) return ;//递归排序结束
//关于为啥下面变量不是 i=l ,j=r 需要看下面代码:
// while(i<j)
// {
// while(arr[++i]<x) ;
// while(arr[--j]>x) ;
// if(i<j) swap(arr[i],arr[j]);
// }
// 在这里,while循环内部使用了前置递增(++i)和前置递减(--j),因此在每次迭代之前就会先递增i,
// 递减j,然后再进行比较。由于i和j的初始值,while循环的第一次迭代就能确保i指向数组中第一个
// 大于等于x的元素,而j指向数组中第一个小于等于x的元素。
// 这样的初始化方式确保了在进入while循环之前,i和j就能够分别指向数组的两侧,这是为了确保在
// 排序过程中,i和j能够逐渐靠拢并找到需要交换的元素。
int i=l-1,j=r+1;
//取数组中间值作为左右划分依据
int x = arr[l+r>>1];
while(i<j)
{
while(arr[++i]<x) ;
while(arr[--j]>x) ;
if(i<j) swap(arr[i],arr[j]);
}
quick_sort(l,j);
quick_sort(j+1,r);
}
int main(){
//初始化数组
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) cin>>arr[i];
//进行快排
quick_sort(0,n-1);
//输出结果
for(int i=0;i<n;i++) cout<<arr[i]<<" ";
return 0;
}
习题2——第k个数
给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k�个数。
输入格式
第一行包含两个整数 n和 k。
第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第 k 小数。
数据范围
1≤n≤100000
1≤k≤n
输入样例:
5 3
2 4 1 5 3
输出样例:
3
#include<iostream>
using namespace std;
const int N=100010;
int arr[N];
//思路仍然是快排的思路,但是本题要求的是第k个元素(从1开始的第k个元素),因此这里需要注意判断临界问题
int quick_sort_k(int l ,int r,int k){
if(l>=r) return arr[l];
int x=arr[l+r>>1];
int i=l-1,j=r+1;
while(i<j){
while(arr[++i]<x);
while(arr[--j]>x);
if(i<j) swap(arr[i],arr[j]);
}
//因为k是从1开始算的,但是这里数组的实际输入从0开始算,因此此处k-1进行对其
if(k-1<=j)
return quick_sort_k(l,j,k);
else
return quick_sort_k(j+1,r,k);
}
int main(){
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++) cin>>arr[i];
cout<<quick_sort_k(0,n-1,k);
return 0;
}