欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[模板题][排序]堆排序

程序员文章站 2022-06-11 12:06:18
...

来源: 模板题

算法标签:堆排序,堆

题目描述

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

输入格式

第一行包含整数n和m。

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

输出格式

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

数据范围

1≤m≤n≤105,
1≤数列中元素≤109

输入样例:

5 3
4 5 1 3 2

输出样例:

1 2 3

堆的基本操作
1.插入一个数字
2.求集合中最小值
3.删除最小值
4.删除任意一个元素
5.修改任意一个元素

思路

我们先理解堆的思路
形如叶子节点不可不满的完全二叉树
如图:
[模板题][排序]堆排序

现在我们来针对这道题书写一下思路
如图:
[模板题][排序]堆排序
1.建堆
2.利用小根堆和down操作m次输出a[1] (堆最小值)

AC代码

#include<iostream>

using namespace std;

const int N=1e5+10;
int a[N];
int n,m;

void down(int u)
{
    int t=u;//新指针,指向子节点
    if(2*u<=n&&a[2*u]<a[t])t=2*u;//左子节点判断
    if(2*u+1<=n&&a[2*u+1]<a[t])t=2*u+1;//右子节点判断 这里不直接交换的原因是 左右两次指向判断直接将t指向了左右子节点中最小的值
    if(t!=u)swap(a[u],a[t]),down(t);//如果确实小于,就交换位子,并递归子节点
}
int main()
{
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)cin>>a[i];
    
    for(int i=n/2;i;i--)down(i);//将所有子节点的节点放导合适位子
    
    while(m--)
    {
        cout<<a[1]<<" ";//输出a[1]
        a[1]=a[n--];//因为a[1]输出过了,此时我们要删除a[1],a[1]被a[n]覆盖,a长度--
        down(1);//将放导a[1]的原a[n]排序到合适位子
    }
    
    return 0;
}