快速排序|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\n", 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:l表示右指针下标边界
参数4:k表示选择第k小的元素

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

猜你喜欢

转载自www.cnblogs.com/fisherss/p/10173400.html
今日推荐