堆排序-模拟堆

输入一个长度为 n的整数数列,从小到大输出前 m 小的数。

输入格式

第一行包含整数 n和 m。

第二行包含 n个整数,表示整数数列。

输出格式

共一行,包含 m个整数,表示整数数列中前 m小的数。

数据范围

1≤m≤n≤100000,
1≤数列中元素≤1000000000

输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3
//如何手写一个堆
//1.插入一个数 head[++size] = x;up(size);
//2.求集合当中的最小值 head[1];
//3.删除最小值 head[1] = head[size];size--;down(1);
//4.删除任意一个元素 head[p] = head[size] ;size--;down(k),up(k);
//5.修改任意一个元素 head [k] = x;down(k);up(k);

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n,m;
int h[N],cnt;
//down操作
void down(int u)
{
    int t = u;
    //首先它的左孩子的在我们的范围内,在判断它与左孩子的大小
    if(u*2<=cnt&&h[u*2]<h[t]) t=u*2;
    //再判断它与右孩子之间的大小
    if(u*2+1<=cnt&&h[u*2+1]<h[t]) t=u*2+1;
    //其实就是判断它是否小于它的左右孩子,如果不是,就进行交换
    if(u!=t)
    {
        swap(h[u],h[t]);
        down(t);
    }
}

int main()
{
    //先把数输入到堆中
    cin >> n >> m;
    for(int i=1;i<=n;i++) cin >> h[i];
    //记录当前堆最后一个位置
    cnt = n;
    //只需对半处理,堆就能排好序
        for(int i =n/2;i;i--) down(i);
    //进行m次询问
    while(m--)
    {
        //最小的数即为堆的开始元素
        cout << h[1] << ' ';
        //输出后将堆的开始元素删除
        //因为顶点元素不好删除,我们将顶点元素转换为最后一个元素,通过cnt--删除
        //转换完之后,我们顶点元素就变成我们最后一个元素,我们只需对顶点元素进行一边down操作就OK
        h[1] = h[cnt];
        cnt--;
        down(1);
    }
    return 0;
}

 

​​​​​​​ 样例演示

输入的原序列:4 5 1 3 2

首先进行堆的初始化:for(int i =n/2;i;i--) down(i);

当i=2时     u=2,t=2

h[u*2]<h[t] t=u*2=4

h[u*2+1]<h[t] t=u*2+1=5

u!=t swap(h[u],h[t])

交换后序列为:4 2 1 3 5

继续down(t) t=5,u=5

因为u*2>cnt u*2+1>cnt

u=t 结束

原序列变为:4 2 1 3 5

当i=1时     u=1,t=1

h[u*2]<h[t] t=u*2=2

h[u*2+1]<h[t] t=u*2+1=3

u!=t swap(h[u],h[t])

交换后的序列为:1 2 4 3 5

继续down(t)

因为u*2>cnt u*2+1>cnt

u=t 结束

原序列变为:1 2 4 3 5

输出环节:

输出h[1]:1

原序列变为:5 2 4 3

Down(1)

原序列变为:2 5 4 3

Down(2)

原序列变为:2 3 4 5(结束)

输出h[2]:2

原序列变为:5 3 4

Down(1)

原序列变为:3 5 4(结束)

输出h[3]:3

原序列变为:4 5;

Down(1) 还是4 5

输出h[4]:4

输出h[5]:5

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值