(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小)。当根节点保存堆中最大值时,称为大根堆;反之,则称为小根堆

二叉堆(Binary Heap)是最简单、常用的堆,是一棵符合堆的性质的完全二叉树。它可以实现

地插入或删除某个值,并且
地查询最大(或最小)值。
一个大根堆

作为一棵完全二叉树,二叉堆完全可以用一个1-index的数组来存储,对于节点pp*2即为左儿子,p*2+1即为右节点。同时,用size记录当前二叉堆中节点的个数。

以数组的方式存储

现在我们考虑如何保证二叉堆的性质不被破坏。实际上,对于一个破坏堆性质的节点,我们可以使其上浮下沉,因为最差也不过是上浮到顶或是下沉到底,所以只需要

的时间就可以使其不再破坏性质。稍后我们会看到,插入和删除都只需要上浮/下沉一个节点。

上浮

很简单,不断与父节点比较,如果比父节点大(以大根堆为例,下同)就与之交换,直到不大于父节点或成为根节点为止。

void swim(int n)
{for (int i = n; i > 1 && heap[i] > heap[i / 2]; i /= 2)swap(heap[i], heap[i / 2]);
}

下沉

类似地,不断与较大的子节点比较,如果比它小就与之交换,直到不小于任何子节点或成为叶子节点为止。之所以要与较大的子节点比较,是为了保证交换上来的节点比两个子节点都大。

int son(int n) // 找到需要交换的那个子节点
{return n * 2 + (n * 2 + 1 <= size && heap[n * 2 + 1] > heap[n * 2]);
}
void sink(int n)
{for (int i = n, t = son(i); t <= size && heap[t] > heap[i]; i = t, t = son(i))swap(heap[i], heap[t]);
}

插入

直接在尾部插入值,然后上浮即可。

void insert(int x)
{heap[++size] = x;swim(size);
}

删除

可以将根节点与最后一个节点交换,使size减1,然后再下沉。

void pop()
{swap(heap[1], heap[size--]);sink(1);
}

查询

直接返回根节点即可。

int top()
{return heap[1];
}

建立

可以从一个数组

地建立堆,只需复制过来然后从底部到顶部依次下沉即可。实际上因为叶子节点不需要下沉,所以可以从
处开始遍历。
void build(int A[], int n) // 从一个(这里是0-index的)数组O(n)地建立二叉堆
{memcpy(heap + 1, A, sizeof(int) * n);size = n;for (int i = n / 2; i > 0; --i)sink(i);
}

设总的往下走的层数为

,则:

因此复杂度是线性的。


使用手写的二叉堆,会比STL提供的priority_queue快一些。此外,了解其原理也有助于理解一些更高级的数据结构。接下来提供一个可以方便地在小根堆和大根堆间切换的模板(利用了宏定义):

namespace heap
{#define maxheap // 如果需要小根堆,把这行注释掉即可
#ifdef maxheap
#define op >
#else
#define op <
#endif
const int MAXN = 1000005;
int heap[MAXN], size;
void swim(int n)
{for (int i = n; i > 1 && heap[i] op heap[i / 2]; i /= 2)swap(heap[i], heap[i / 2]);
}
int son(int n)
{return n * 2 + (n * 2 + 1 <= size && heap[n * 2 + 1] op heap[n * 2]);
}
void sink(int n)
{for (int i = n, t = son(i); t <= size && heap[t] op heap[i]; i = t, t = son(i))swap(heap[i], heap[t]);
}
void push(int x)
{heap[++size] = x;swim(size);
}
void pop()
{swap(heap[1], heap[size--]);sink(1);
}
int top()
{return heap[1];
}
void build(int A[], int n)
{memcpy(heap + 1, A, sizeof(int) * n);size = n;for (int i = n / 2; i > 0; --i)sink(i);
}
} // namespace heap


Pecco:算法学习笔记(目录)​zhuanlan.zhihu.com

大顶堆删除最大值_算法学习笔记(47): 二叉堆相关推荐

  1. l2-004 这是二叉搜索树吗?_算法学习笔记(45): 二叉搜索树

    二叉搜索树(Binary Search Tree, BST)是一种常用的数据结构,在理想情况下,它可以以 的复杂度完成一系列修改和查询,包括: 插入一个数 删除一个数 查询某数的排名(排名定义为比该数 ...

  2. 基于MVS的三维重建算法学习笔记(二)— 立体视觉的几何基础总结

    基于MVS的三维重建算法学习笔记(二)- 立体视觉的几何基础总结 声明 概述 1. 常见三维数据类型 2. 三维形状的几种表达形式 3. 三维空间刚体运动 4. 李群和李代数 5. 相机标定 6. 非 ...

  3. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列

    (为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...

  4. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  5. 狄利克雷卷积_算法学习笔记(35): 狄利克雷卷积

    这篇笔记完全是数学内容,但它是之后一些算法的基础. 所谓狄利克雷卷积,是定义在数论函数( 的函数)间的一种二元运算,可这样定义: 也常常等价地写作: 为了之后讨论方便,先定义一些常用的数论函数的符号: ...

  6. 莫队算法学习笔记(二)——带修莫队

    前言:什么是莫队 莫队算法,是一个十分优雅的暴力. 普通的莫队可以轻松解决一些离线问题,但是,当遇上了一些有修改操作的问题,普通莫队就无能为力了. 于是,改进后的莫队--带修莫队就这样产生了. L i ...

  7. 学习笔记:二叉搜索树的验证

    方法一(低效): 最开始想的办法是,先写 求二叉树中最大值的函数,和一个求二叉树中最小值的函数,然后调用这两个函数 写出 验证二叉搜索树的函数(因为要左边小于右边嘛),结果 时间复杂度特别大,老是超时 ...

  8. c++ 链表_算法学习笔记 - 链表 - 单链表的粗糙实现

    常用的链表有单链表.双链表.循环链表. 概念看得再多,理解得再多,也不一定能够写得出来.所以动动手,多练习才是提升能力的关键. 有朋友留言说道:建议大家在实现之前的思考时间不要太长.一是先用自己能想到 ...

  9. 线性求逆元模板_算法学习笔记(9):逆元

    https://zhuanlan.zhihu.com/p/105467597在数论中,如果 ,我们就说 和 在模 意义下互为乘法逆元,记作 . 逆元有什么用呢?我们常常遇到一些题目要求结果对一个大质数 ...

最新文章

  1. 出国读博前希望有人告诉我
  2. 实时计算框架 Flink 新方向:打造「大数据+AI」 未来更多可能
  3. 隐私计算,企业数字化转型的BUFF之争
  4. 青龙羊毛——小虎饿了(偷的)
  5. python处理excel教程实例-python如何处理excel数据
  6. vue 动态变量名_【告别复制粘贴】动态模板生成小技巧
  7. 【渝粤教育】国家开放大学2018年春季 0529-22T高级英语阅读(1) 参考试题
  8. 极简的js点击组图切换效果
  9. mysql日志文件的类型和作用_Mysql日志文件和日志类型介绍
  10. 易语言MYQQ框架群管机器人如何获取用户信息
  11. 项目管理六大制约因素_项目管理有哪些主要风险及如何控制?
  12. [Essay]看《Re:从零开始的异世界生活》的一些感想
  13. 如何使用计算机远程电脑,远程控制电脑,教您如何远程控制电脑
  14. 计算机网络拓扑有,计算机网络拓扑
  15. @media screen and 不起作用原因汇总。(转载)
  16. HDU 1885 Key Task 国家压缩+搜索
  17. Tyvj 1047 乘积最大
  18. Delphi2010开发DataSnap服务器(一)
  19. 100的阶乘有多少0
  20. canvas实现画板工具

热门文章

  1. flask蓝图的使用
  2. python中eval与json.loads对json的处理
  3. Redis安装配置和介绍
  4. 《你的灯亮着么》五六篇
  5. Weblogic 10.3.6 for linux 集群安装
  6. SharePoint数据表组件错误
  7. linux c 实现函数 trim 除去字符串首尾空格
  8. python jenkins库 api简介
  9. mysql 查看版本
  10. Windows的驱动开发模型