算法笔记5067ProblemA 求第k大数

本文介绍了一种利用随机选择算法求解无序序列中第k大数的方法,通过随机选取主元进行划分,实现高效查找。文章提供了完整的C++代码实现,并分享了在数组开辟和函数作用域方面的常见错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

给定一个长度为n(1≤n≤1,000,000)的无序正整数序列,以及另一个数k(1≤k≤1,000,000)(关于第k大的数:例如序列{1,2,3,4,5,6}中第3大的数是4。)

输入

第一行两个正整数m,n。
第二行为n个正整数。

输出

第k大的数。

样例输入

6 3
1 2 3 4 5 6

样例输出

4

代码展示

#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 1000010;
int a[maxn]; // a存放所有整数

// 选取随机主元,对区间[left,right]进行划分
int randPartition(int a[], int left, int right)
{
    int p = round(1.0 * rand() / RAND_MAX * (right - left) + left);
    swap(a[p], a[left]);
    // 以下是划分过程
    int temp = a[left];
    while(left < right)
    {
        while(left < right && a[right] > temp)
            right--;
        a[left] = a[right];
        while(left < right && a[left] <= temp)
            left++;
        a[right] = a[left];
    }
    a[left] = temp;
    return left;
}

// 随机选择算法,从a[left,right]中返回第k大的数
int randSelect(int a[], int left, int right, int k)
{
    if(left == right)
        return a[left]; // 边界
    int p = randPartition(a, left, right); // 划分后的主元位置为p
    int m = right - p + 1; // a[p]是a[left,right]中的第m大
    if(k == m)
        return a[p];
    if(k > m)
        return randSelect(a, left, p - 1, k - m);
    else
        return randSelect(a, p + 1, right, k);
}

int main()
{
    srand((unsigned)time(NULL)); // 初始化随机数种子
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    printf("%d", randSelect(a, 0, n - 1, m));
    return 0;
}

小结

出现了两个错误分享一下:

  1. 开辟大数组时应放在main函数之前,即声明一个全局数组。全局变量在静态存储区分配内存,局部变量是在栈上分配内存空间,一般堆栈默认是1M,int a[1000000]的大小是4*1000000,将近4M,远远大于1M,编译连接的时候不会有问题,但运行时堆栈溢出,程序异常终止。
  2. 函数的作用域只是从定义的地方开始的。也就是说,在函数定义行之上,你是无法使用该函数的。

ps:

在算法笔记这本书中149页随机选择算法应改为求第k小的数。求第k大的数只需要修改randSelect函数(参照上面的代码)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值