算法第三周 : 很大的数组的第k小(快速排序)

Description

求数组的第k小,数字数量非常多。

Input

每组数据给出n m k表示有n个数,求第k小,数组的数字由以下规则得到:

ai = mi mod  (109+7), i = 1, 2, ..., n

其中 1 ≤ n, m ≤ 5 × 107, 1 ≤ k ≤ n,数据保证得到的数组元素大部分互不相等。

Output

输出第k小的数

Sample Input

3 2 2

Sample Output

4

我们可以采用快速排序算法的一种变式来实现

首先先回顾一下快速排序算法,先贴一个快排的代码

 

void QuickSort(int arr[], int begin, int end)
{
    //只有一个数或者区间不存在时
    if (begin >= end) return;
    int left = begin;
    int right = end;
    //选取左边第一个为key
    int key = begin;
    while (begin<end)
    {
        //右边选小
        while (arr[end] >= arr[key] && begin < end)
        {
            end--;
        }
        //左边选大
        while (arr[begin] <= arr[key] && begin < end)
        {
            begin++;
        }
        swap(arr[begin], arr[end]);
    }
    //此时left和right指针已经相遇
    swap(arr[key], arr[end]);
    //递归左右区间
    key = end;
    QuickSort(arr, left, key - 1);
    QuickSort(arr, key + 1, right);
}

 我们观察一下,第一趟快速排序结束后数组是什么样子的

 当第一趟排序完成之后,我们将key放在了数组中的某一个位置,在这个位置,key左边的数都比它小,key右边的数都比它大。所以key的下标就对应了它在数组中是第k小的数。

所以我们并不需要完成整个快速排序的过程,因为只关心每次key在数组中的下标,至于a[left,key-1]和a[key+1,right]之间的数据有序与否,我们并不关心。

如图所示 [3 1 2 5 4 6 9 7 10 8],key(6)在数组中是第六个数,这代表着它是第六小的数,至于左半部分[3 1 2 5]它们之间不是有序,并不影响,我们知道它们比key小就行了

因此我们改变一下代码即可

if (target_pos + 1 == k) return arr[target_pos];
    else if (target_pos + 1 > k) return QuickSort(arr, left, target_pos - 1, k);
    else return QuickSort(arr, target_pos + 1, right, k);

完整代码:

#include<iostream>
using namespace std;
int a[50000000];
int QuickSort(int arr[], int begin, int end, int k)
{
    int left = begin;
    int right = end;
    //选取左边第一个为key
    int key = begin;
    while (begin < end)
    {
        //右边选小
        while (arr[end] >= arr[key] && begin < end)
        {
            end--;
        }
        //左边选大
        while (arr[begin] <= arr[key] && begin < end)
        {
            begin++;
        }
        swap(arr[begin], arr[end]);
    }
    //此时left和right指针已经相遇
    swap(arr[key], arr[end]);
    key = end;
    int target_pos = end;
    //数组下标从0开始,所以需要+1
    if (target_pos + 1 == k) return arr[target_pos];//找到第k小的数了,直接返回
    //递归左半区间
    else if (target_pos + 1 > k) return QuickSort(arr, left, target_pos - 1, k);
    //递归右半区间
    else return QuickSort(arr, target_pos + 1, right, k);
}

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值