快速排序-分治
-
确定分界点 在一个区间[l,r]中 挑选l 或者 r 或者 (l+r)/2 或者随机 为x
-
调整区间 <=x 和 >=x
- 可以通过设置两个数组,遍历整个区间,将>=和<=x的数分别放在两个数组中,再合并数组到区间
- 用两个指针,一个在最右边,一个在最左边,左边的向前遍历,当遇到>=x的数时,停止移动,动用最右边的指针,同理找到<=x的数,两个指针的数据交换位置,如此重复直到两个指针相遇(或者交叉)
-
递归处理左右两端
-
时间复杂度(平均复杂度):nlogn (n分成每份占1,需要logn,一共n层)
-
代码:
#include<stdio.h>
void quick_sort(int q[], int l, int r) {
if(l >= r) return;//如果l和r已经交叉,则说明数列已经被分割成单元素数列,排序完毕
int x = q[(l + r) / 2];
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) {
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
int main() {
int n;
printf("请输入排序数字的个数:");
scanf("%d", &n);
int q[n];
int i;
printf("请输入数字:");
for(i = 0; i < n; i++) {
scanf("%d", &q[i]);
}
quick_sort(q, 0, n-1);
printf("结果为:");
for(i = 0; i < n; i++) {
printf("%d ", q[i]);
}
return 0;
}
快速选择
-
首先通过快速选择分为左右两边,然后如果k<=left的个数,则只需要递归左边 如果k>左边的个数,则只需要递归右边
-
时间复杂度:O(n)
-
代码
#include<stdio.h>
int n, k;
int q[100010];//10^5
int quick_sort(int q[], int l, int r, int k) {
if(l == r) return q[l];
//当首位下标交叉时,说明只有一个元素,这个数就为第K个数,直接返回
int x = q[l];
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) {
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
int sl = j - l + 1;//设左侧小于x部分的队列长度为sl
if(k <= sl) return quick_sort(q, l, j, k);
return quick_sort(q, j + 1, r, k - sl);
}
int main() {
scanf("%d %d", &n, &k);
int i;
for(i = 0; i < n; i++) {
scanf("%d", &q[i]);
}
printf("%d", quick_sort(q, 0, n - 1, k));
return 0;
}