概念
堆的底层实际上是一棵完全二叉树,可以用数组实现。
二叉树的一种,满足以下条件:
- 任意节点大于或小于它的所有子节点(大根堆、小根堆)
- 总是一完全树,即除了最底层,其它层的节点都被元素填满
将根节点最大的堆叫做最大堆
或大根堆
,根节点最小的堆叫做最小堆
或小根堆
。
![87273b746356ab4ed741be082dfbb10d.png](https://i-blog.csdnimg.cn/blog_migrate/df202896aaacb70698e58e913acd27a3.jpeg)
将数组第一个元素置空
,为了方便计算。这样我们就可以从下标1
开始,下标变量为i
,那么:
- 左子节点位置是
2*i
- 右子节点位置是
2*i+1
- 父节点位置是
Math.floor(i/2)
堆(以大顶堆为例)相关的操作主要有:
- 大顶堆调整(Max-Heapify),将堆的末端子节点做调整,使得子节点永远小于父节点;
- 创建大顶堆(Build-Max-Heap),将堆中所有数据调整位置,使其成为大顶堆;
- 堆排序(Heap-Sort),移除在堆顶的根节点,并做大顶堆调整的迭代运算。
大顶堆调整
/**
* 从index开始检查并保持大顶堆
* @param arr 待检查数组
* @param i 检查的起始下标
* @param size 堆大小
*/
function maxHeapify(arr, i, size) {
let left = 2 * i
let right = left + 1
//左右孩子中较大的一个
let maxlr = -1
//无左右孩子节点
if (left > size && right > size) {
return
}
//只有左孩子节点
if (left <= size && right > size) {
maxlr = left
}
//只有右孩子节点
if (right <= size && left > size) {
maxlr = right
}
//同时有左右孩子节点
if (left <= size && right <= size) {
maxlr = arr[left] < arr[right] ? right : left
}
if (arr[i] < arr[maxlr]) {
swap(arr, i, maxlr)
maxHeapify(arr, maxlr, size)
}
}
function swap(arr, i, j) {
let temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
非递归写法:
/**
* 从i开始检查并保持大顶堆
* @param arr 待排数组
* @param i 检查的起始下标
* @param size 堆大小
*/
function maxHeapify2(arr, i, size) {
let left, right, maxlr = -1
while (i < size) {
left = 2 * i
righ