堆 (heap) 与优先队列
基础知识
- 完全二叉树的回顾
- 父节点的编号存在可计算的关系,因此不需要边存储的信息
- 可以用连续空间存储
- 堆的概念
- 一种基于完全二叉树的结构
- 大顶堆和小顶堆
- 大顶堆:任意三元组之间,父节点都大于子节点
- 小顶堆:任意三元组之间,父节点都小于子节点
- 堆顶元素为最大值或最小值
堆的基本操作(手撕小顶堆)
class Heap { constructor(data) { this.data = data; this.compartor = (a, b) => a - b; this.heapify(); } // 堆的长度 size() { return this.data.length; } // 初始化小顶堆 heapify() { if (this.size() < 2) return; for (let i = 1; i < this.size(); i++) { this.bubbleUp(i); } } // 两两交换 swap(i, j) { if (i === j) return; [this.data[i], this.data[j]] = [this.data[j], this.data[i]]; } // 获取堆顶元素 peek() { if (!this.size()) return null; return this.data[0]; } // 添加元素 offer(val) { this.data.push(val); this.bubbleUp(this.size() - 1); } // 删除元素 poll() { let res = this.data[0]; this.data[0] = this.data.pop(); if (this.size()) { this.bubbleDown(0); } return res; } // 上浮(向上调整) bubbleUp(index) { while (index) { let prentIndex = (index - 1) >> 1; if (this.compartor(this.data[index], this.data[prentIndex]) < 0) { this.swap(index, prentIndex); index = prentIndex; } else { break; } } } // 下沉(向下调整) bubbleDown(index) { // 获取最大下标,保证不会交换出界 let lastIndex = this.size() - 1; while (index < lastIndex) { let leftIndex = index * 2 + 1; let rightIndex = index * 2 + 2; let findIndex = index; if (leftIndex <= lastIndex && this.compartor(this.data[leftIndex], this.data[findIndex]) < 0) { findIndex = leftIndex; } if (rightIndex <= lastIndex && this.compartor(this.data[rightIndex], this.data[findIndex]) < 0) { findIndex = rightIndex; } if (index !== findIndex) { this.swap(index, findIndex); index = findIndex; } else { break; } } }}let arr = [8, 7, 6];let H = new Heap(arr);H.offer(9);H.poll();console.log(H.data);
经典面试题