特点
- 堆是一种特殊的完全二叉树。
- 所有的节点都大于等于(最大堆)或小于等于(最小堆)的子节点;
- 用数组表示最大堆;
- 左侧子节点的位置是 2*index+1
- 右侧子节点的位置事 2*index+2
- 父节点的位置 index-1/2
操作
高效快速的找出最大值和最小值; 找出第K个最大的元素;
演示
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 (i - 1) >> 1;
}
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;
}
}
练习题
215. 数组中的第K个最大元素
// 第k个最大元素,使用最小堆;
// 构建一个最小的堆,并依次将数组的值插入到堆中。 当堆得容量超过K,就删除堆顶; 插入结束后堆顶就是第k个最大元素
var findKthLargest = function (nums, k) {
const min = new MinHeap(); // 构建最小堆
nums.forEach((item) => {
min.insert(item);
if (min.size() > k) { // 容量超出了,删除栈顶
min.pop();
}
});
return min.peek(); // 返回栈顶
};
347. 前 K 个高频元素
var topKFrequent = function (nums, k) {
const map = new Map();
nums.forEach((i) => {
map.set(i, map.has(i) ? map.get(i) + 1 : 1);
});
const list = Array.from(map).sort((a, b) => b[1] - a[1]);
return list.slice(0, k).map((item) => item[0]);
};
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 (i - 1) >> 1;
}
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[parentIndex].value > this.heap[index].value
) {
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[leftIndex].value < this.heap[index].value
) {
this.swap(leftIndex, index);
this.shiftDown(leftIndex);
}
if (
this.heap[rightIndex] &&
this.heap[rightIndex].value < this.heap[index].value
) {
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;
}
}
var topKFrequent = function (nums, k) {
const map = new Map();
nums.forEach((item) => {
map.set(item, map.has(item) ? map.get(item) + 1 : 1);
});
const min = new MinHeap();
map.forEach((value, key) => {
min.insert({ key, value });
if (min.size() > k) {
min.pop();
}
});
return min.heap.slice(0, k).map((item) => item.key);
};
23. 合并K个升序链表
// 构建最小堆
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 (i - 1) >> 1;
}
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[parentIndex].val > this.heap[index].val
) {
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[leftIndex].val < this.heap[index].val
) {
this.swap(leftIndex, index);
this.shiftDown(leftIndex);
}
if (
this.heap[rightIndex] &&
this.heap[rightIndex].val < this.heap[index].val
) {
this.swap(rightIndex, index);
this.shiftDown(rightIndex);
}
}
insert(value) {
this.heap.push(value);
this.shiftUp(this.heap.length - 1);
}
pop() {
if (this.size() === 1) return this.heap.shift();
const top = this.heap[0];
this.heap[0] = this.heap.pop();
this.shiftDown(0);
return top;
}
peek() {
return this.heap[0];
}
size() {
return this.heap.length;
}
}
var mergeKLists = function (lists) {
const res = new ListNode(0);
const heap = new MinHeap();
let p = res;
lists.forEach((item) => {
if (item) heap.insert(item);
});
while (heap.size()) {
const node = heap.pop();
p.next = node;
p = p.next;
if (node.next) heap.insert(node.next);
}
return res.next;
};