SDUT-3401 数据结构实验之排序四:寻找大富翁(堆排序)

13 篇文章 0 订阅

数据结构实验之排序四:寻找大富翁

Time Limit: 200MS  Memory Limit: 512KB
Problem Description

2015胡润全球财富榜调查显示,个人资产在1000万以上的高净值人群达到200万人,假设给出N个人的个人资产值,请你快速找出排前M位的大富翁。

Input

首先输入两个正整数N( N ≤ 10^6)和M(M ≤ 10),其中N为总人数,M为需要找出的大富翁数目,接下来给出N个人的个人资产,以万元为单位,个人资产数字为正整数,数字间以空格分隔。

Output

一行数据,按降序输出资产排前M位的大富翁的个人资产值,数字间以空格分隔,行末不得有多余空格。

 

Example Input
6 3
12 6 56 23 188 60
Example Output
188 60 56
Hint

请用堆排序完成。 

Author

xam

参考:https://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html

参考:http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621/

此题因为数组较大,使用高效排序依然可能超时,但因为M较小,所以由此入手,输入前M个数后,每次循坏找M个中最小的和新输入的

进行比较,若小于新输入的,则替换。

#include <bits/stdc++.h>///数组下标从0开始
using namespace std;
int a[12];
void adjust(int s,int e)///调整堆
{
    int temp=a[s];
    for(int i=s*2+1;i<=e;i*=2)/*为什么等于e:e不一定等于m,而且下面if有判断i<e,所以不用担心数组越界;i*=2:因为调整过后可能孩子堆被破坏,所以数组下标跳到孩子继续调整*/
    {
        if(i<e&&a[i]<a[i+1])///找到两个孩子中较大的
            i++;
        if(temp>a[i])///若大于两个孩子,则无需进行后面的判断,退出循环
            break;
        a[s]=a[i];
        s=i;///完成一次调整后,堆顶变为i
    }
    a[s]=temp;///中途循坏退出,则再把调整前的堆顶记录插入到现在的堆顶
}

void Heap(int n)
{
    for(int i=(n/2)-1; i>=0; i--)///依照从下到上的顺序构建堆,因为n/2之后的是叶子结点,所以无需调整
    {
        adjust(i,n);
    }
    for(int i=n-1; i>=1; i--)///共n个结点,所以调整n-1次
    {
        swap(a[0],a[i]);
        adjust(0,i-1);
    }
}

int main()
{
    std::ios::sync_with_stdio(false);///防止超时
    int n,m,x,k=0,l;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
    {
        cin>>x;
        if(k<m)
            a[k++]=x;
        else
        {
            l=0;
            for(int j=1; j<m; j++)
            {
                if(a[l]>a[j])///记录m个数中的最小值
                    l=j;
            }
            if(a[l]<x)///若最小的小于x,就把他替换掉
                a[l]=x;
        }
    }
    Heap(m);///只对前m个构建堆
    for(int i=m-1; i>=0; i--)
    {
        if(i==m-1)
            cout<<a[i];
        else
            cout<<' '<<a[i];
    }
    cout<<endl;
    return 0;
}

#include <bits/stdc++.h>///数组下标从1开始
using namespace std;
int a[100];
void adjust(int i,int n)///调整堆
{
    int left=i*2;///左子树结点
    int right=i*2+1;///右子树结点
    int ma=i;
    if(i<=n/2)///n/2之后的是叶子结点,无需调整
    {
        if(left<=n&&a[left]>a[ma])///找到三个点中的最大的
        {
            ma=left;
        }
        if(right<=n&&a[right]>a[ma])
        {
            ma=right;
        }
        if(ma!=i)///若左右子树的值大于根,就交换两者的值
        {
            swap(a[i],a[ma]);
            adjust(ma,n);///若交换了值,则需要调整他们的孩子使孩子也是堆
        }
    }
}

void Heap(int n)
{
    for(int i=(n/2); i>=1; i--)///依照从下到上的顺序构建堆,因为n/2之后的是叶子结点,所以无需调整
    {
        adjust(i,n);
    }
    for(int i=n; i>=2; i--)///共n个结点,所以调整n-1次
    {
        swap(a[1],a[i]);
        adjust(1,i-1);
    }
}

int main()
{
    std::ios::sync_with_stdio(false);///防止超时
    int n,m,x,k=1,l;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
    {
        cin>>x;
        if(k<m+1)
            a[k++]=x;
        else
        {
            l=1;
            for(int j=2; j<k; j++)
            {
                if(a[l]>a[j])///记录m个数中的最小值
                    l=j;
            }
            if(a[l]<x)///若最小的小于x,就把他替换掉
                a[l]=x;
        }
    }
    Heap(m);///只对前m个构建堆
    for(int i=m; i>=1; i--)
    {
        if(i==m)
            cout<<a[i];
        else
            cout<<' '<<a[i];
    }
    cout<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值