快速排序|2018年蓝桥杯B组题解析第五题-fishers

标题:快速排序

以下代码可以从数组a[]中找出第k小的元素。

它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。

请仔细阅读分析源码,填写划线部分缺失的内容。

#include <stdio.h>
#include<cstdlib>

int quick_select(int a[], int l, int r, int k) {
	int p = rand() % (r - l + 1) + l; //l~r之间的一个随机数 
	int x = a[p];//x的值随机数a[p]的值 
	{int t = a[p]; a[p] = a[r]; a[r] = t;} //交换随机数a[p]和高位右边第一个数 
	int i = l, j = r; //i左指针 j右指针
	while(i < j) {
		while(i < j && a[i] < x) i++;// 最后i==j 或者 a[i]>=x
		if(i < j) {//如果a[i]>=随机数x 
			a[j] = a[i]; //选一个比x大的数 放到高位 
			j--;
		}
		while(i < j && a[j] > x) j--;// 最后j==i 或者 a[i]<=x
		if(i < j) {//如果a[i]<=随机数x
			a[i] = a[j]; //选一个比x小的数 放到低位
			i++;
		}
	}
	a[i] = x;
	p = i;//这里改了p的值 说明会用到p 
	if(i - l + 1 == k) return a[i];
	if(i - l + 1 < k) return quick_select(_________); //填空
	else return quick_select(a, l, i - 1, k);//a数组不变 k不变 
}
	
int main()
{
	int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
	printf("%d
", quick_select(a, 0, 14, 5));
	return 0;
}

注意:只填写划线部分缺少的代码,不要抄写已经存在的代码或符号。

答案:a, p+1, r, k-(i-l+1) 或者 a, p, r, k-i+l

思路:首先学会快速排序的划分思想(看下张图理解快排的双指针)

左指针l:确认i左边都小于当前选定的枢纽
右指针r:确定j右边都大于当前选定的枢纽
枢纽:快速排序单遍扫描,可以选第一个元素为枢纽,也可以随机选元素作为枢纽。

这道题要我们找到数组中第k小的元素,
思路和快速排序一样:划分,分解,合并

关键在于划分:

先看参数的作用:
这里的参数l表示左指针,r表示右指针(功能同快速排序一致)
参数1:a表示数组不变
参数2:l表示左指针下标边界
参数2:r表示右指针下标边界
参数4:k表示选择第k小的元素

回到快速排序的各个指针的变化:
l~i区间内都是比枢纽小的,一共i-l+1个元素;
i+1~r都是比枢纽大的
如果i-l+1比k大,说明要在l~i-1中找;还是找第k个元素
如果i-l+1比k小,说明要在i+1~r某个值中找,这个值是多少呢?要看还需要找到新一轮递归中找第多少小的元素,这里新参数k就等于 原k减去当前一轮的l~i的个数 即k-(i-l+1)
原文地址:https://www.cnblogs.com/fisherss/p/10173400.html