一、最小堆
1、结构特性:完全二叉树(所有层除最后一层外均填满)
2、堆序特性:父节点值 ≤ 子节点值
3、操作时间复杂度:插入/删除 O(log n),取最小值 O(1)
// 最小二叉堆
class MinHeap{
constructor(){
this.heap = []
}
// 添加元素
insert(val) {
this.heap.push(val)
this.up(this.heap.length-1)
}
// 上(前)移动
up(index) {
if(index===0) return;
const parentIndex = this.getParentIndex(index);
if(this.heap[parentIndex]>this.heap[index]){
this.swap(parentIndex,index)
this.up(parentIndex)
}
}
// 下(后)移动
down(index) {
if(index>=this.heap.length) return ;
const leftIndex = this.getLeftIndex(index)
const rightndex = this.getRightIndex(index)
if(leftIndex < this.heap.length && this.heap[index]>this.heap[leftIndex]){
this.swap(leftIndex,index)
this.down(leftIndex)
}
if(rightndex < this.heap.length && this.heap[index]>this.heap[rightndex]) {
this.swap(rightndex,index)
this.down(rightndex)
}
}
// 交换位置
swap(i1,i2){
const temp = this.heap[i1]
this.heap[i1] = this.heap[i2]
this.heap[i2] = temp
}
// 删除堆顶
pop() {
this.heap[0] = this.heap.pop();
this.down(0)
}
// 获取堆顶
peek(){
return this.heap[0]
}
size(){
return this.heap.length
}
// 获取父级节点-index
getParentIndex(index) {
return Math.floor((index -1) /2 );
}
// 获取左侧子节点-index
getLeftIndex(index) {
return index * 2 + 1
}
// 获取右侧子节点-index
getRightIndex(index) {
return index * 2 + 2
}
}
应用场景:
优先队列实现
Dijkstra 最短路径算法
求 Top K 小元素(结合最大堆)
堆排序(修改为最大堆)
二、最大堆
1、结构特性:完全二叉树(所有层除最后一层外均填满)
2、堆序特性:父节点值 ≥子节点值
// 最大堆
class MaxHeap {
constructor() {
this.heap = [];
}
// 获取父节点索引(与最小堆相同)
_parentIndex(index) {
return Math.floor((index - 1) / 2);
}
// 交换元素(与最小堆相同)
_swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
// 插入元素(逻辑相同,但比较方向改变)
insert(value) {
this.heap.push(value);
this._bubbleUp(this.heap.length - 1);
}
// 上浮调整(关键修改点:将 < 改为 >)
_bubbleUp(index) {
while (index > 0) {
const parentIndex = this._parentIndex(index);
if (this.heap[index] <= this.heap[parentIndex]) break; // 比较方向反转
this._swap(index, parentIndex);
index = parentIndex;
}
}
// 提取最大值(原extractMin改名)
extractMax() {
if (this.heap.length === 0) return null;
const max = this.heap[0];
const last = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = last;
this._sinkDown(0);
}
return max;
}
// 下沉调整(关键修改点:选择更大的子节点)
_sinkDown(index) {
const leftChild = 2 * index + 1;
const rightChild = 2 * index + 2;
let largest = index; // 变量名改为largest
if (leftChild < this.heap.length &&
this.heap[leftChild] > this.heap[largest]) { // 比较方向反转
largest = leftChild;
}
if (rightChild < this.heap.length &&
this.heap[rightChild] > this.heap[largest]) { // 比较方向反转
largest = rightChild;
}
if (largest !== index) {
this._swap(index, largest);
this._sinkDown(largest);
}
}
// 其他方法保持不变
size() {
return this.heap.length;
}
peek() {
return this.heap[0] ?? null;
}
}
应用场景:
优先队列(高优先级先出)
Top K 大元素问题(结合最小堆)
堆排序算法(升序排序)
滑动窗口最大值(特殊场景优化)