Skip to content

简介

堆是一种特殊的完全二叉树,分为最大堆和最小堆,因为完全二叉树的特性,通常用数组表示

时间复杂度:

  • 插入:O(log n)
  • 删除最大或最小元素:O(log n)
  • 获取最大或最小元素(peek):O(1)

用途:优先队列、堆排序、Dijkstra 最短路径算法和 Prim 最小生成树算法(图算法)

INFO

  • 完全二叉树:树节点的填充是从上层到下层依次完成的,在每一层,节点会从左到右按顺序填满
  • 最大堆:每个父节点的值大于或等于其任何子节点的值
  • 最小堆:每个父节点的值小于或等于其任何子节点的值
  • 优先队列:总是优先出队优先级最高的元素,而不是最早进入队列的元素(应用场景:任务调度、路径搜索、事件处理)

WARNING

数据结构中的堆内存管理中的堆是两个概念,不能混为一谈!

最大堆

ts
class MaxHeap<T> {
    private readonly __heap: Array<T> = [];

    public insert(value: T): void {
        this.__heap.push(value);
        this.__bubbleUp();
    }

    public extractMax(): T | null {
        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.__bubbleDown();
        }

        return max;
    }

    public peek(): T | null {
        return this.__heap[0] ?? null;
    }

    private __bubbleUp(): void {
        let index = this.__heap.length - 1;
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            if (this.__heap[index] <= this.__heap[parentIndex]) {
                break;
            }

            [this.__heap[index], this.__heap[parentIndex]] = [
                this.__heap[parentIndex],
                this.__heap[index]
            ];
            index = parentIndex;
        }
    }

    private __bubbleDown(): void {
        let index = 0;
        const length = this.__heap.length;
        while (index < length) {
            const leftChildIndex = 2 * index + 1;
            const rightChildIndex = 2 * index + 2;
            let max = index;

            if (leftChildIndex < length && this.__heap[leftChildIndex] > this.__heap[max]) {
                max = leftChildIndex;
            }

            if (rightChildIndex < length && this.__heap[rightChildIndex] > this.__heap[max]) {
                max = rightChildIndex;
            }

            if (max === index) {
                break;
            }

            [this.__heap[max], this.__heap[index]] = [this.__heap[index], this.__heap[max]];
            index = max;
        }
    }
}

const maxHeap = new MaxHeap<number>();
maxHeap.insert(10);
maxHeap.insert(20);
maxHeap.insert(5);
maxHeap.insert(15);

console.log(maxHeap.peek());
console.log(maxHeap.extractMax());
console.log(maxHeap.peek());

最小堆

ts
class MinHeap<T> {
    private readonly __heap: Array<T> = [];

    public insert(value: T): void {
        this.__heap.push(value);
        this.__bubbleUp();
    }

    public extractMin(): T | null {
        if (this.__heap.length === 0) {
            return null;
        }

        const min = this.__heap[0];
        const last = this.__heap.pop()!;
        if (this.__heap.length > 0) {
            this.__heap[0] = last;
            this.__bubbleDown();
        }

        return min;
    }

    public peek(): T | null {
        return this.__heap[0] ?? null;
    }

    private __bubbleUp(): void {
        let index = this.__heap.length - 1;
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            if (this.__heap[index] >= this.__heap[parentIndex]) {
                break;
            }

            [this.__heap[index], this.__heap[parentIndex]] = [
                this.__heap[parentIndex],
                this.__heap[index]
            ];
            index = parentIndex;
        }
    }

    private __bubbleDown(): void {
        let index = 0;
        const length = this.__heap.length;
        while (index < length) {
            const leftChildIndex = 2 * index + 1;
            const rightChildIndex = 2 * index + 2;
            let min = index;

            if (leftChildIndex < length && this.__heap[leftChildIndex] < this.__heap[min]) {
                min = leftChildIndex;
            }

            if (rightChildIndex < length && this.__heap[rightChildIndex] < this.__heap[min]) {
                min = rightChildIndex;
            }

            if (min === index) {
                break;
            }

            [this.__heap[min], this.__heap[index]] = [this.__heap[index], this.__heap[min]];
            index = min;
        }
    }
}

const minHeap = new MinHeap<number>();
minHeap.insert(10);
minHeap.insert(20);
minHeap.insert(5);
minHeap.insert(15);

console.log(minHeap.peek());
console.log(minHeap.extractMin());
console.log(minHeap.peek());

基于 MIT 许可发布