大顶堆删除最大值_算法学习笔记(47): 二叉堆
堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小)。当根节点保存堆中最大值时,称为大根堆;反之,则称为小根堆。
二叉堆(Binary Heap)是最简单、常用的堆,是一棵符合堆的性质的完全二叉树。它可以实现
作为一棵完全二叉树,二叉堆完全可以用一个1-index的数组来存储,对于节点p
,p*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): 二叉堆相关推荐
- l2-004 这是二叉搜索树吗?_算法学习笔记(45): 二叉搜索树
二叉搜索树(Binary Search Tree, BST)是一种常用的数据结构,在理想情况下,它可以以 的复杂度完成一系列修改和查询,包括: 插入一个数 删除一个数 查询某数的排名(排名定义为比该数 ...
- 基于MVS的三维重建算法学习笔记(二)— 立体视觉的几何基础总结
基于MVS的三维重建算法学习笔记(二)- 立体视觉的几何基础总结 声明 概述 1. 常见三维数据类型 2. 三维形状的几种表达形式 3. 三维空间刚体运动 4. 李群和李代数 5. 相机标定 6. 非 ...
- 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列
(为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...
- 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序
拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...
- 狄利克雷卷积_算法学习笔记(35): 狄利克雷卷积
这篇笔记完全是数学内容,但它是之后一些算法的基础. 所谓狄利克雷卷积,是定义在数论函数( 的函数)间的一种二元运算,可这样定义: 也常常等价地写作: 为了之后讨论方便,先定义一些常用的数论函数的符号: ...
- 莫队算法学习笔记(二)——带修莫队
前言:什么是莫队 莫队算法,是一个十分优雅的暴力. 普通的莫队可以轻松解决一些离线问题,但是,当遇上了一些有修改操作的问题,普通莫队就无能为力了. 于是,改进后的莫队--带修莫队就这样产生了. L i ...
- 学习笔记:二叉搜索树的验证
方法一(低效): 最开始想的办法是,先写 求二叉树中最大值的函数,和一个求二叉树中最小值的函数,然后调用这两个函数 写出 验证二叉搜索树的函数(因为要左边小于右边嘛),结果 时间复杂度特别大,老是超时 ...
- c++ 链表_算法学习笔记 - 链表 - 单链表的粗糙实现
常用的链表有单链表.双链表.循环链表. 概念看得再多,理解得再多,也不一定能够写得出来.所以动动手,多练习才是提升能力的关键. 有朋友留言说道:建议大家在实现之前的思考时间不要太长.一是先用自己能想到 ...
- 线性求逆元模板_算法学习笔记(9):逆元
https://zhuanlan.zhihu.com/p/105467597在数论中,如果 ,我们就说 和 在模 意义下互为乘法逆元,记作 . 逆元有什么用呢?我们常常遇到一些题目要求结果对一个大质数 ...
最新文章
- 出国读博前希望有人告诉我
- 实时计算框架 Flink 新方向:打造「大数据+AI」 未来更多可能
- 隐私计算,企业数字化转型的BUFF之争
- 青龙羊毛——小虎饿了(偷的)
- python处理excel教程实例-python如何处理excel数据
- vue 动态变量名_【告别复制粘贴】动态模板生成小技巧
- 【渝粤教育】国家开放大学2018年春季 0529-22T高级英语阅读(1) 参考试题
- 极简的js点击组图切换效果
- mysql日志文件的类型和作用_Mysql日志文件和日志类型介绍
- 易语言MYQQ框架群管机器人如何获取用户信息
- 项目管理六大制约因素_项目管理有哪些主要风险及如何控制?
- [Essay]看《Re:从零开始的异世界生活》的一些感想
- 如何使用计算机远程电脑,远程控制电脑,教您如何远程控制电脑
- 计算机网络拓扑有,计算机网络拓扑
- @media screen and 不起作用原因汇总。(转载)
- HDU 1885 Key Task 国家压缩+搜索
- Tyvj 1047 乘积最大
- Delphi2010开发DataSnap服务器(一)
- 100的阶乘有多少0
- canvas实现画板工具