1.1 快速排序
AcWing 785. 快速排序
题目
给定你一个长度为n的整数数列。
请你使用快速排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在1~109109范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1 ≤ n ≤ 100000
输入样式:
5
3 1 2 4 5
输出样例:
3 1 2 4 5
解题思路
快速排序(quick sort)采用的是”分治"的思想,主要步骤为以下三步:
-
选取合适的基准点(pivot)
-
移动元素,使基准点左边的元素小于基准点大小,基准点右边的元素大于基准点大小
-
对左右两边分别进行递归运算
注意事项
原本基准点可以随机选择,但是由于AcWing的OJ说明了基准点选择为边界会导致程序运行超时,因此我们的基准点选择为中点。
程序代码
#include <stdio.h>
void quick_sort(int arr[], int l, int r);
int main() {
int n;
scanf("%d", &n);
int arr[n];
for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
quick_sort(arr, 0, n-1);
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
return 0;
}
void quick_sort(int arr[], int l, int r) {
if (l >= r) return;
int i = l-1, j = r+1, pivot = arr[(l+r)/2];
while (i < j) {
do i++; while (arr[i] < pivot);
do j--; while (arr[j] > pivot);
if (i < j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
quick_sort(arr, l, j);
quick_sort(arr, j+1, r);
}
AcWing 786. 第K个数
题目
给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列的第k小的数是多少。
输入格式
第一行包含两个整数 n 和 k。
第二行包含 n 个整数(所有整数均在1~109109范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第k小数。
数据范围
1 ≤ n ≤ 100000 1 ≤ n ≤ 100000,
1 ≤ k ≤ n
输入样式:
5 3
2 4 1 5 3
输出样例:
3
解题思路
此题采用快速排序的思想,但是要注意的是,由于k是一个定值,因此,在第一次排序完成后,我们便可以计算出第k小数在哪一个区间,只需要在它所在区间内在进行递归排序即可。不需要两边都进行递归排序,那样会增加复杂度。
程序代码
#include <stdio.h>
int n, k;
int quick_sort(int arr[], int l, int r, int k);
int main() {
scanf("%d %d", &n, &k);
int arr[n];
for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
printf("%d", quick_sort(arr, 0, n-1, k));
return 0;
}
int quick_sort(int arr[], int l, int r, int k) {
if (l >= r) return arr[l];
int i = l-1, j = i+1, pivot = arr[(l+r)/2];
while (i < j) {
do i++; while (arr[i] < pivot);
do j--; while (arr[j] > pivot);
if (i < j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
if (k <= j-l+1) return quick_sort(arr, l, j, k);
else return quick_sort(arr, j+1, r, k-(j-l+1));
}
arr[i] = arr[j];
arr[j] = tmp;
}
}
if (k <= j-l+1) return quick_sort(arr, l, j, k);
else return quick_sort(arr, j+1, r, k-(j-l+1));
}