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

数据结构实验之排序四:寻找大富翁
Time Limit: 200 ms Memory Limit: 512 KiB
Problem Description
2015胡润全球财富榜调查显示,个人资产在1000万以上的高净值人
群达到200万人,假设给出N个人的个人资产值,请你快速找出排前M位的大富翁。
Input
首先输入两个正整数N( N ≤ 10^6)和M(M ≤ 10),其中N为总人数,M为需要找出的大富翁数目
接下来给出N个人的个人资产,以万元为单位,个人资产数字为正整数,数字间以空格分隔。
Output
一行数据,按降序输出资产排前M位的大富翁的个人资产值,数字间以空格分隔,行末不得有多
余空格。
Sample Input
6 3
12 6 56 23 188 60
Sample Output
188 60 56

先说一下这题的思路吧,首先,这道题如果直接对所有数据进行队排的话是会超时的,所以这里有一个更加巧妙的方法,就是我们可以先把前m个数据直接放进堆里,然后我们维护一个小顶堆,当输入完m个数据之后每当我们输入一个数据,我们拿这个数据与当前堆的堆顶(也就是堆里的最小值)进行对比,如果大于堆顶,就让把这个值赋值给堆顶,然后我们对这个堆进行调整,维护一个小顶堆,这样当所有值都输入完之后,这个小顶堆一定是最大的m个数,这时候我们只需要对这个堆进行排序就可以了。

堆排的思路(拿小顶堆来说,排序后是由大到小的顺序):
1.我们知道的是这个小顶堆的堆顶一定是整个堆里最小的值,我们把它和堆里面最后一个元素进行交换。
2.这样这个堆的最后一个元素就是最小的元素了。
3.然后我们把最后一个元素以外的堆再次调整为一个小顶堆。
4.重复上述操作。

#include<stdio.h>
#include<string.h>
int size,a[100000];		//size代表堆里面有多少元素
void adjust(int n)		//调整函数(维护小顶堆)
{
    int i,p,t;
    for(i=1; i*2<=n; i=p)		//这里的结束条件为当前节点没有儿子
    {
        if(a[i*2+1]<a[i*2]&&i*2+1<=n)		//我们需要在左右儿子里面找到一个
            p=i*2+1;						//较小的值,并与该节点比较,注意
        else								//这里要判断是否有右儿子
            p=i*2;
        if(a[i]>a[p])
        {
            t=a[i];
            a[i]=a[p];
            a[p]=t;
        }
        else
            break;
    }
}
void cp(int x)		//仅仅对于这题而言可以这样做,这里是m个数据之后每输入一个数据
{					//就进行比较,如果大于堆顶元素就进行赋值操作并维护
    if(x>a[1])
    {
        a[1]=x;
        adjust(size);
    }
}
void hsort()				//这里是最后一步,输入完所有数据之后,对这个小顶堆
{							//进行堆排序,因为题目要求从大到小输出
    int i,t;
    for(i=size; i>=1; i--)
    {
        t=a[i];				//前面思路里提到的堆排步骤的实现
        a[i]=a[1];
        a[1]=t;
        adjust(i-1);
    }
}
int main()
{
    int n,m,i,x;
    scanf("%d %d",&n,&m);
    for(i=1; i<=m; i++)
    {
        scanf("%d",&x);
        a[++size]=x;
    }
    adjust(size);			//可能会想到,前m个数据根本不需要先调整,因为我们在后
    for(i=m+1; i<=n; i++)	//面插入一个数之后也会进行调整,所以这里是多余的,但
    {						//仔细一想的话,如果我们在这里不进行调整的话,我们是无
        scanf("%d",&x);		//法保证后面的值与堆内最小值比较的。我们当然可以用插入函数
        cp(x);				//来避免此操作。
    }
    hsort();					//堆排
    for(i=1;i<=m;i++)
    {
        if(i==m)
        printf("%d\n",a[i]);
        else
        printf("%d ",a[i]);
    }
    return 0;
}

写的并不仔细,如果想看具体堆的操作可以看这里

猜你喜欢

转载自blog.csdn.net/qq_44011946/article/details/85379721