数据结构基础7:堆

文章详细介绍了如何手写实现堆数据结构,包括插入元素、获取最小值、删除最小值、删除任意元素以及修改元素等操作。堆是基于完全二叉树的,通常用数组存储,这里重点讨论了小根堆,确保每个节点的值小于或等于其子节点的值。通过down和up函数维护堆的性质。
摘要由CSDN通过智能技术生成

手写一个堆需要能实现哪些操作:

  1. 插入一个数
  2. 求集合当中的最小值
  3. 删除最小值
  4. 删除任意元素(STL无法实现)
  5. 修改任意元素(STL无法实现)

堆的底层是完全二叉树

小根堆:每个点都是小于等于左右儿子的值(根节点就是最小值)

存储方式:用数组存,1号点为根节点,x节点的左儿子节点下标为2x, x节点的右儿子节点下标为2x+1

更新的时候,每个点和左右儿子的较小值进行交换,以实现up和down操作

插入:heap[++ size] = x; up(size) 在堆的最后位置放x,up里面传要进行操作的位置

堆中的最小值:heap[1]

删除最小值: heap[1] = heap[size]; size – ; down(1); 用最后一个元素来覆盖最小的元素

删除任意元素:heap[k] = heap[size]; size --; down(k); up(k);

修改任意元素: heap[k] = x; down(k); up(k);

带映射的堆不是很常用,即不用实现 h e a p _ s w a p heap\_swap heap_swap操作,一般只需要实现最基本的堆即可

堆算法模板:

#include <string.h>
#incldue <algorithm>

// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], siz;

// 交换两个点,及其映射关系
void heap_swap(int a, int b)
{
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    int t = u;
    if (u * 2 <= siz && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= siz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        heap_swap(u, t);
        // 当对于第几个插入没有执念的时候,直接swap(h[u], h[t])也可以
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u] < h[u / 2])
    {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

// 向堆中插入元素
h[++ siz] = x;  
up(siz);

// 向堆中插入第k个元素x
h[++ siz] = x;
ph[++ m] = siz, hp[siz] = m;
up(siz);

// 堆中的最小值
h[1]
    
// 删除堆的最小值
h[1] = h[siz];
// 或者heap_swap(1, siz);
siz --;     
down(1);

// 删除任意元素
h[k] = h[siz];	 
siz --;	
down(k), up(k);

// 删除第k个插入的元素,注意先把ph[k]先存起来
k = ph[k];
heap_swap(k, siz);
siz --;
down(k), up(k);

// 修改任意元素
h[k] = x;	
down(k), up(k);

// 修改第k个插入的元素为x
k = ph[k];
h[k] = x;
down(k), up(k);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

钰见梵星

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

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

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

打赏作者

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

抵扣说明:

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

余额充值