一;什么是堆?
堆是一种特殊的完全二叉树,所有的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点
二;JS中的堆
1.JS中通常用数组表示堆。
2.左侧子节点的位置是 2 * index + 1
3.右侧子节点的位置是 2 * index + 2
4.父节点的位置是(index - 1)/ 2
三;堆的应用
堆能高效、快速的找出最大值和最小值,时间复杂度为O(1);
找出第 K 个最大(小)元素
四;JS实现堆的基本操作(入堆,删除堆顶,堆长度,取堆尾)
class MinHeap {
constructor() {
this.heap = [];
}
// 交换父节点与子节点
swap(i1, i2) {
const temp = this.heap[i1];
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
// 获取当前节点的父节点
getParentIndex(i) {
return Math.floor((i - 1) / 2);
}
getLeftIndex(i) {
return i * 2 + 1;
}
getRightIndex(i) {
return i * 2 + 2;
}
// 向堆尾添加元素需要进行上移操作
// 上移操作,比较父节点与子节点的大小,若父节点比子节点大,则交换俩节点
// 目的是让新加入的节点符合堆的数据结构
shiftUp(index) {
if (index == 0) return;
const parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
this.swap(parentIndex, index);
this.shiftUp(parentIndex);
}
}
// 删除堆头操作要进行下移操作
// 删除堆头 实际上是移除了堆的末尾元素,将末尾元素值赋值给堆头元素
// 从堆头进行下移操作,目的删除堆头元素后不会影响堆的数据结构
shiftDown(index) {
const leftIndex = this.getLeftIndex(index);
const rightIndex = this.getRightIndex(index);
if(this.heap[leftIndex] < this.heap[index]) {
this.swap(leftIndex,index);
this.shiftDown(leftIndex);
}
if(this.heap[rightIndex] < this.heap[index]) {
this.swap(rightIndex,index);
this.shiftDown(rightIndex);
}
}
// 向堆中插入节点
insert(value) {
// 将值插入到堆的末尾
this.heap.push(value);
// 上移操作,与父节点进行比较
this.shiftUp(this.heap.length - 1)
}
// 删除堆头节点
pop() {
// 移除堆尾,用堆尾节点替代堆头节点
// 不能直接删除堆头,否则会破坏堆的结构
this.heap[0] = this.heap.pop();
// 执行下移操作
this.shiftDown(0);
}
// 获取堆顶
peek(){
return this.heap[0];
}
// 获取堆的长度
size(){
return this.heap.length;
}
}
const h = new MinHeap();
h.insert(3)
h.insert(2)
h.insert(1)
h.pop();