堆 \color{red}{\huge{堆}}

堆是一种可以 快速查找一个数据集合中最大值和最小值的数据结构 \color{purple}{快速查找一个数据集合中最大值和最小值的数据结构} 快速查找一个数据集合中最大值和最小值的数据结构。并且当新进入或者新去除元素之后可以 自行调整内部元素从而完成自动更新最值。 \color{purple}{自行调整内部元素从而完成自动更新最值。} 自行调整内部元素从而完成自动更新最值。

①.堆的表现形式

  1. 堆其实是由 完全二叉树 \color{blue}{完全二叉树} 完全二叉树所建造成的,在该完全二叉树中满足所有父节点都小于(大于)它对应的孩子节点。在这里插入图片描述

这就是堆的逻辑存储方式,依托于二叉树。因为这些性质也就决定了,堆的最值都是在祖宗节点处体现。

  1. 一维数组存储堆 \color{olive}{\huge{一维数组存储堆}} 一维数组存储堆
    就像一维数组存储完全二叉树一样去存储堆即可。
    在这里插入图片描述

需要注意的是, 堆在数组中存储下标一定要从 1 开始存储 \color{red}{堆在数组中存储下标一定要从1开始存储} 堆在数组中存储下标一定要从1开始存储,从 0 0 0开始会有很麻烦的边界检验问题。

  1. 堆数据更新 ( 默认小顶堆 ) \color{olive}{\huge{堆数据更新(默认小顶堆)}} 堆数据更新(默认小顶堆)
    d o w n 操作: down操作: down操作:如果一个数据比它下面位置的数据要大,那么它应该“下沉”。这时需要 d o w n down down操作来调换元素位置。
    u p 操作: up操作: up操作:如果一个数据比它上面的数据要小,那么它应该“上浮”。这时需要 u p up up操作来调换元素位置。
    d o w n down down u p up up操作进行数据调整的时候, 一定是在父节点、左右孩子节点中最值进行交换 \color{red}{一定是在父节点、左右孩子节点中最值进行交换} 一定是在父节点、左右孩子节点中最值进行交换,这样才能保证交换完之后堆结构仍然不被破坏。

②. 堆具体操作

首先是两个最为基础的操作。
d o w n 操作 \color{blue}{\huge{down操作}} down操作
K e y : Key: Key从三个节点之中选择最小的值,交换到父节点即可。

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);
    }
}

u p 操作 \color{blue}{\huge{up操作}} up操作
K e y : Key: Key每次和对应的父节点交换即可。

void up(int u)
{
    while(u / 2 && h[u / 2] > h[u])
    {
        swap(h[u / 2] , h[u]);
        u /= 2;
    }
    
    return ;
}

1. 插入一个数 \color{red}{\huge{插入一个数}} 插入一个数
堆中插入数据的时候,就是在堆尾插入数据,之后进行 u p up up操作,如果能 u p up up u p up up,不能 u p up up说明它现在插入的位置就是刚好在的位置。

heap[++size] = x;       //堆尾插入元素
up(size);   //将size对应的元素进行up操作调整位置

2. 取出当前集合中元素最小值 \color{red}{\huge{取出当前集合中元素最小值}} 取出当前集合中元素最小值
根据堆的性质就可以直接从堆顶得出。

heap[1];

3. 删除最小值 \color{red}{\huge{删除最小值}} 删除最小值
堆的物理存储是依托于一维数组,所以在数组头部进行删除操作太过于麻烦。可以先将尾部元素与头部元素进行交换,然后直接删除尾部的元素,最后对头部元素进行 d o w n down down操作就可以了。

heap[1] = heap[size];
size--;
down(1);

4. 删除任意一个元素 \color{red}{\huge{删除任意一个元素}} 删除任意一个元素
仿照 3 3 3操作即可

heap[k] = heap[size];
size--;
down(k);    //反正down和up都只能满足一个
up(k);      //索性全部搞一次

5. 修改任意一个元素 \color{red}{\huge{修改任意一个元素}} 修改任意一个元素
修改值之后,利用 d o w n down down u p up up调整元素即可、

heap[k] = x;
down(k);
up(k);

③. 完整代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n,m;
int h[N],cnt;

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);
    }
    
    return ;
}

void up(int u)
{
    while(u / 2 && h[u / 2] > h[u])
    {
        swap(h[u / 2],h[u]);
        u /= 2;
    }
    
    return ;
}

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);
    }
    
    while(m--)
    {
        cout << h[1] << " ";
        h[1] = h[cnt--];
        down(1);
    }
    
    puts("");
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值