堆(数据结构)

121 阅读1分钟

概念:1.堆是一种特殊的完全二叉树
2.所有的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点

特点:
1.js中通常使用数组表示堆
2.左侧子节点的位置是: 2*index + 1
3.右侧子节点的位置是: 2*index + 2
4.父节点位置是(index-1)/ 2

最小堆

class MinHeap {
    constructor() {
        this.heap = [];
    }
    swap(index1, index2) {
        const temp = this.heap[index1];
        this.heap[index1] = this.heap[index2];
        this.heap[index2] = temp;
    }
    // 获取父节点
    getParentIndex(index) {
        return (index - 1) >> 1;
    }
    // 获取左节点
    getLeftIndex(index) {
        return (index << 1) + 1
    }
    // 获取右节点
    getRightIndex(index) {
        return (index << 1) + 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;
    }
}

最大堆

class MaxHeap {
    constructor() {
        this.h = [];
    }
    swap(parentIndex, childrenIndex) {
        [this.h[parentIndex], this.h[childrenIndex]] = [this.h[childrenIndex], this.h[parentIndex]];
    }
    getParentIndex(childrenIndex) {
        return (childrenIndex - 1) >> 1;
    }
    upshift(index) {
        if (index === 0) return;
        let parentIndex = this.getParentIndex(index);
        // 小于区别最小堆
        if (this.h[parentIndex] < this.h[index]) {
            this.swap(parentIndex, index);
            this.upshift(parentIndex);
        }
    }
    getChildrenLeftIndex(parentIndex) {
        return (parentIndex << 1) + 1;
    }
    getChildrenRightIndex(parentIndex) {
        return (parentIndex << 1) + 2
    }
    downshift(index) {
        const leftIndex = this.getChildrenLeftIndex(index);
        const rightIndex = this.getChildrenRightIndex(index);
        // 大于区别最小堆
        if (this.h[leftIndex] > this.h[index]) {
            this.swap(leftIndex, index);
            this.downshift(leftIndex);
        }
       // 大于区别最小堆
        if (this.h[rightIndex] > this.h[index]) {
            this.swap(rightIndex, index)
            this.downshift(rightIndex);
        }
    }

    insert(val) {
        this.h.push(val);
        this.upshift(this.h.length - 1);
    }
    peek() {
        return this.h[0];
    }
    size() {
        return this.h.length;
    }

    pop() {
        this.h[0] = this.h.pop();
        this.downshift(0);
    }
}