堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;
由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。
这种数据结构具有以下性质。
任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。堆总是一棵完全树。
即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
常见的堆有二叉堆、斐波那契堆等。
解释
以上是 维基百科 关于堆的描述,转换为人话就是大概这么几条:
- 堆在本质上是一种
二叉树
- 但是它是用
数组
的形式来描述二叉树
- 按照二叉树的
每一排
依次进行序号
的排序 - 且堆在
非最后子叶
的情况下不能只有一个元素
- 对序号为
k
的节点 它的左节点序号2k+1
它的右节点序号2k+2
它的父节点的序号是k/2
向下取整
如下图所示,由上至下 每一行按照序号进行排序 形成一个数组[100, 19, 36, 17, 3, 25, 1, 2, 7]
。
关于 且堆在非最后子叶的情况下不能只有一个元素
的解释是:
根据图中的树节点,如果有最后的2
和 7
节点, 那么 36
节点不能只有一个节点, 必须有两个节点
, 这样才能保证堆序号
的连续性和正确性
除此之外, 堆还分为:
-
最大堆
- 父节点总大于子节点
- 顶部是最大值
-
最小堆
- 父节点总小于子节点
- 顶部是最小值
堆的操作
- 堆化
最大堆化 max-heapify
维护最大堆
性质的过程 和子节点
不断比较
将最大值
和自己交换
最小堆化 min-heapify
维护最小堆
性质的过程
JS建堆并实现最大堆化
class MaxHeap {
constructor(data, max=10000){
this.list = new Array(max) // 堆的最大值
for(let i = 0; i < data.length; i++){
this.list[i] = data[i]
}
this.heap_length = data.length; // 堆中真实元素个数
this.build(); // 开始建堆
}
build(){
// 首先获取最后一个元素的序号/索引
// 注意向上取整
let IND = Math.floor(this.heap_length / 2) + 1;
while(IND >= 0){
this.max_heapify(IND--) // 树形结构 由下往上
}
}
max_heapify(index){
// 默认index为父级序号
let parent_ind = index
// 获取最大子元素序号 先默认左子元素为最大
let max_child_ind = parent_ind * 2 + 1
while(max_child_ind <= this.heap_length - 1){
// 判断1: 子与子的大小关系
if(
max_child_ind < this.heap_length - 1 &&
this.list[max_child_ind] < this.list[max_child_ind + 1]
){
// 如果左子元素小于右子元素 将最大序号指向右子元素
max_child_ind = max_child_ind + 1
}
// 判断2: 判断子与父的大小关系
if(this.list[parent_ind] >= this.list[max_child_ind]){
// 如果本身父元素就大于子元素 不做处理 直接break
break;
}else{
// 父元素小于子元素 将父元素与子元素进行交换
let temp = this.list[parent_ind];
this.list[parent_ind] = this.list[max_child_ind];
this.list[max_child_ind] = temp
}
}
}
}
测试一下:
const data = [12, 15, 2, 4, 3, 8, 7, 6, 5];
const test = new MaxHeap(data);
console.log(test);
// 打印结果:
MaxHeap {
list: [ 15, 12, 8, 6, 3, 2, 7, 4, 5, <9991 empty items> ],
heap_length: 9
}
即,满足了最大堆化
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。