堆的运用(输出前m大的数据)

本文深入探讨了堆数据结构的原理,包括大顶堆和小顶堆的概念,并详细介绍了如何通过堆解决实际问题,如从大量数据中快速找出前N大的元素。文章提供了具体的算法实现,展示了堆在数据处理和排序中的应用。

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

堆的运用


堆是一棵完全二叉树,一般将其分为大顶堆和小顶堆。小顶堆是指子结点的值大于父结点的值;大顶堆就是堆的子结点的值都小于父结点的值。

在实现的时候,常常使用基于数组的堆(由于是完全二叉树,所以元素在数组中是连续的)。如果一个结点的编号为n,那么,其对应的左右子结点的编号分别是2n和2n+1。如果一个结点的编号为n,则其父结点的编号为n/2。

  1. 添加操作
    如果要添加一个元素,首先把这个元素放在最后,然后与其父结点比较,如果不满足堆的性质,则交换。如果不满足堆的性质,则继续进行下去即可。
  2. 删顶
    首先把最后一个元素与顶交换,再删除最后一个元素。如果顶不满足堆的性质,则与左右儿子比较,与较小(大)的儿子交换,然后继续下去,直至得到一个正确的堆。

问题
如果一个文件内存储了10亿个商品的销量数据,请你在其中
找出前1000大的数据。

分析
用前1000个数据建立大小为1000的小顶堆,后面的数据与顶堆的第一个数据进行比较,若比第一个数据大,则交换,再顶堆排序得到新的小顶堆;否则舍弃该数据。

#include <bits/stdc++.h>
using namespace std;

#define N 1005
int a[N]={0};

int main()
{
    int deta,i,k,m=10;
    memset(a,0,sizeof(a));
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    for(i = 1; i <= m; i++)
        scanf("%d", &a[i]);
    //小顶堆排序
    for(i = 2; i <= m; i++)
    {
        k = i; //第k个元素沿着路径进行小顶堆排序
        while(k > 0)
        {
            if(k/2 <= 0 || a[k] >= a[k/2])
                break;
            swap(a[k], a[k/2]);
            k = k/2;
        }
    }
//    for(i = 1; i <= m; i++)
//        printf("%d ", a[i]);
//    printf("\n");
    while(scanf("%d", &deta)==1)
    {
        if(deta>a[1])
        {
            swap(a[1], deta);
            k=1;
            while(2*k<=m)
            {
                    if(a[k]<=a[2*k]&&a[k]<=a[2*k+1]) break;
                    if(a[2*k]<a[2*k+1])
                    {
                        swap(a[k], a[2*k]);
                        k=2*k;
                    }
                    else
                    {
                        swap(a[k], a[2*k+1]);
                        k=2*k+1;
                    }
            }
            //检错:防止剩余的0参与交换
            if(a[k/4]>a[k/2])
                swap(a[k], a[k/2]);
        }
//        for(i = 1; i <= m; i++)
//            printf("%d ", a[i]);
//        printf("\n");
    }
    for(i = 1; i <= m; i++)
        printf("%d ", a[i]);
    return 0;
}


运行结果(取比较小的m=10来验证)
测试数据:89 85 91 13 29 68 48 94 49 47 48 85 79 51 99 1 81 76 1 51
运行结果:68 81 76 89 85 91 79 94 99 85

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值