heap
手写实现 Heap 结构
文章参考
参考链接:二叉堆详解实现优先级队列
著作权归原作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Heap {
    data: ListNode[];
    comparator: Function;
    constructor(
        comparator = (a: ListNode, b: ListNode) => a.val < b.val,
        data = []
    ) {
        this.comparator = comparator;
        this.data = data;
        this.heapify();
    }
    // 堆化
    heapify() {
        // 1个或者0个,没必要堆化了
        if (this.size() < 2) return;
        // 这为啥从中间开始?值堆化一半就够了?
        for (let i = Math.floor(this.size() / 2) - 1; i >= 0; i--) {
            this.bubbleDown(i);
        }
    }
    // 元素往上走
    bubbleUp(index: number) {
        while (index > 0) {
            const pIndex = (index - 1) >> 1; //注意:父节点位置,很有意思的一步
            // 往上走,所以要比较他和他爹谁大
            if (this.comparator(this.data[index], this.data[pIndex])) {
                this.swap(index, pIndex); //跟他爹换换位置
                index = pIndex;
            } else {
                break;
            }
        }
    }
    // 元素往下沉
    bubbleDown(index: number) {
        const lastIndex = this.size() - 1;
        while (true) {
            const leftIndex = index * 2 + 1; //左子节点index
            const rightIndex = index * 2 + 2; // 右子节点index
            let findIndex = index; //当前bubbleDown节点的位置
            // 左节点跟根节点对比,选择符合条件的
            if (
                leftIndex <= lastIndex &&
                this.comparator(this.data[leftIndex], this.data[findIndex])
            ) {
                findIndex = leftIndex;
            }
            // 右节点跟根节点对比,选择符合条件的上去
            if (
                rightIndex <= lastIndex &&
                this.comparator(this.data[rightIndex], this.data[findIndex])
            ) {
                findIndex = rightIndex;
            }
            // 说明有变化,做了交换
            if (index !== findIndex) {
                this.swap(index, findIndex);
                index = findIndex;
            } else {
                break;
            }
        }
    }
    // 交换两个元素位置
    swap(i: number, j: number) {
        [this.data[i], this.data[j]] = [this.data[j], this.data[i]];
    }
    // 返回堆顶元素
    peek() {
        return this.size() >= 0 ? this.data[0] : null;
    }
    // 往堆里面添加一个值
    offer(value: ListNode) {
        this.data.push(value); //添加一个元素,相当于放到了最右下角的子节点,index为数组最后一个
        this.bubbleUp(this.size() - 1);
    }
    // 移除堆顶元素,重新构建堆,返回删除的元素
    poll() {
        if (this.size() === 0) {
            return null;
        }
        // 把第一个扔到最后面去,然后把最后一个扔到第一个,然后让第1个往下沉。
        this.swap(0, this.size() - 1);
        let result = this.data.pop()!;
        this.bubbleDown(0);
        return result;
    }
    // 堆的大小
    size() {
        return this.data.length;
    }
}