n 个数中最小的 k 个数


1. 描述

输入 n 个整数,输出其中最小的 k 个。


2. 解法

一般的方法是用选择排序,直到k个最小的数产生。时间复杂度为O(nk),空间复杂度为O(n)。

或者是对这n个数用快速排序从小到大排好序后,输出前k个数,时间复杂度为O(nlogn),空间复杂度为O(n)。

但若数据量非常庞大,以至于整个内存空间都放不下,上面两种方法就无能为力了。


利用堆排序可以解决空间复杂度的问题,用O(k)的空间复杂度就可以解决。

下面的算法输入n个数,打印出最小的k个数。

(1) 若 k >= n,直接打印出这n个数,否则执行第(2)步。

(2) 把输入的前k个数放到A[1..k]中,创建这n个数的大顶堆,则A[1]为这 k 个数中最大的数。

(3) 若已输入的数的个数等于n执行第(5)步,否则输入下一个数。比较这个数与A[1]的大小,若这个数大于等于A[1],重新返回(3)。否则执行(4)。

(4) 令A[1]等于这个数,调整这k个数使其重新成为大顶堆。返回第(3)步。

(5) 结束循环,打印A[1..k]。程序结束。


代码如下:

void min_k_nums(int n, int k)
{
    int A[k + 1], i, j, temp;
    printf("input %d numbers: \n", n);
    for (i = 1; i <= n; i++)
    {
        if (i <= k) {                     //前k个数直接存放
            scanf("%d", &A[i]);
            continue;
        } 
        if (i == k + 1) {
            for (j = k >> 1;j >= 1; j--)  //对前k个数创建大顶堆
                heapAdjust(A, j, k);
        } 
        scanf("%d", &temp);
        if (temp < A[1]) {                //比较输入的数与堆顶元素的大小
            A[1] = temp;
            heapAdjust(A, 1, k);          //调整使其重新成为大顶堆
        }// if
    }// for
    printf("The least k numbers are: \n");//输出结果
    for (i = 1;i <= k; i++)
        printf("%d ", A[i]);
    printf("\n");
}

其中调整成为大顶堆的算法如下:

void heapAdjust(int A[], int s, int m)
{
    int j, rc;
    rc = A[s];
    for (j = s << 1; j <= m; j <<= 1)
    {
        if (j < m && A[j] < A[j + 1])
            j++;
        if (rc >= A[j])
            break;
        A[s] = A[j];
        s = j;
    }
    A[s] = rc;
}  

此算法见<堆排序>。


测试结果如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值