Heap 堆
Heap: 可以迅速找到一堆数中的最大值或者最小值的数据结构,注意找最大值或最小值,两者只能取其一。
将根节点最大的堆叫做大顶堆或大根堆,根节点最小的堆叫小顶堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
假设是大顶堆,则常见操作(API)及其对应复杂度:
- find-max:O(1)
- delete-max:O(logN)
- insert(create): O(logN) 或者 O(1)
不同实现的比较:en.wikipedia.org/wiki/Heap_(…
二叉堆
通过完全二叉树来实现(注意:不是二叉搜索树);二叉堆(大顶)它满足以下性质:
- 是一颗完全树🌲(根和每个节点都是满的,最下面一层最后一个节点之前所有的坑位都要占满)
- 树中任意节点的值总是 >= 其子节点的值
- 它的实现相对比较容易,但是其实二叉堆的时间复杂度在所有堆类型里只是刚刚及格。
以下就为完全二叉树,除了最下面一层不是丰满状态以外,每一层都是满的,而且任意节点的值都是大于等于其子节点的。注意,这里70是最下面一层最后一个节点,70之前元素必须满才行,如果去掉50就不是完全树了,但是去掉70是可以的,去掉70之后50变成最后一个节点了,50之前节点满就行。

由于它的这个性质,我们就能保证根节点就是最大的节点。
二叉堆实现细节
- 二叉堆一般都通过"数组"来实现
- 因为二叉堆是从根节点到左子,再到右子依次排下来,假设"第一个元素"在数组中的索引为0的话,上图中二叉堆对应数组为[110, 100, 90, 40, ...],则父节点和子节点的位置关系如下:
- 索引为i的左孩子的索引是(2 * i + 1)
- 索引为i的右孩子的索引是(2 * i + 2)
- 索引为i的父节点的索引是 Math.floor((n - 1) / 2) (向下取整)
二叉堆插入元素 Insert(O(logN))
- 新元素一律插入到堆的尾部
- 依次向上调整到整个堆的结构(一直到根即可)
插入新元素会先添加到堆的尾部,也就是插到40的左子节点。
然后要把85依次往上浮动,如果85大于他的父亲节点,那么就跟它的父亲节点交换位置,直到走到根节点。整个操作最坏会遍历一侧的堆,也就是O(log2的N次方)
二叉堆删除堆顶操作 Delete Max (logn)
- 将堆尾的元素替换到顶部(即堆顶被替换删除掉)
- 依次从根部向下调整整个堆的结构(挪上去然后调整下来)