蓝桥杯必看 【手撕模板】三分钟搞懂 <堆排序>

堆是一个满二叉树,根据其性质我们就可以知道堆是连续存储的(在数组中),但是日常做算法题的时候自己写链式存储是比较麻烦的,所以最近重点学习一下数组实现堆

实现堆(数组)

例题

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

输入格式
第一行包含整数 n 和 m。

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

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

数据范围
1≤m≤n≤105,
1≤数列中元素≤109
输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3

1. 递归法

运用递归时 ,有时候需要使用临时变量 方便判断递归的结束条件

1为根节点
#include<iostream>
#include<cstring>
#include<algorithm>
const int N = 1000010;
int n,m;
using namespace std;
int mysize , h[N];
int down (int p)
{
    int tp = p;//创建临时变量 用来运算
    int child = p *2 ;
    if(child  <= mysize && h[child] < h[tp])  tp= child;
    if(child +1 <= mysize && h[child +1 ] < h[tp])  tp = child +1 ;
    if(tp != p) 
    {
        swap(h[tp],h[p]);
        down(tp);
    }

}

int main()
{
    cin >> n >> m;  
    for(int i = 1 ; i <= n ; i ++)    scanf("%d",&h[i]);
    mysize = n;
    
    for(int i = n/2  ; i ; i --)      down(i);
    while(m -- )    
    {
        cout<<h[1]<<' ';
        h[1] = h[mysize];
        mysize --;
        down(1);
    }
}

0 为根节点
#include<iostream>
#include<cstring>
#include<algorithm>

const int N = 1000010;
int n,m;
using namespace std;
int mysize , h[N];

void down(int parent)
{
    int tp  = parent;//运用递归需要使用临时变量 方便判断
    int child = (parent << 1) +1 ;

    if(child < mysize && h[child+1] < h[child])  child ++;
    if(child < mysize && h[child] < h[tp])  tp = child;
    if(tp != parent)   
    {
        swap(h[parent],h[tp]);
        down(tp);//从当前child节点往下递归
    }

    
}

int main()
{
    cin >> n >> m;  
    for(int i = 0 ; i < n ; i ++)   
    {
        scanf("%d",&h[i]);
        mysize++;
    }
    
    while(n --)  down(n);

    while(m -- )    
    {
        cout<<h[0]<<' ';
        h[0] = h[mysize -1];
        mysize --;
        down(0);
    }
}

2. 迭代法
1为根节点
void down(int parent)
{
    int child = parent << 1;
    
    while(child <= mysize)
    {
        if(child <=mysize && h[child+1] < h[child ])  child ++;
        if(child <=mysize && h[child] < h[parent])    
        {
            swap( h[parent] , h[child]);
            parent = child;
            child = parent << 1;
        }
        else break;
    }
}
0为根节点
#include<iostream>
#include<cstring>
#include<algorithm>

const int N = 1000010;
int n,m;
using namespace std;
int mysize , h[N];

void down(int parent)
{
    int child = (parent << 1) +1 ;
    
    while(child < mysize)
    {
        if(child < mysize && h[child+1] < h[child])  child ++;
        if(child < mysize && h[child]   < h[parent])    
        {
            swap( h[parent] , h[child]);
            parent = child;
            child = (parent << 1) +1 ;
        }
        else break;
    }
}

int main()
{
    cin >> n >> m;  
    for(int i = 0 ; i < n ; i ++)   
    {
        scanf("%d",&h[i]);
        mysize++;
    }
    
    while(n --)  down(n);

    while(m -- )    
    {
        cout<<h[0]<<' ';
        h[0] = h[mysize -1];
        mysize --;
        down(0);
    }
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值