二叉堆(Binary Heap)

堆是完全二叉树,我们使用下标从1开始的数组来表示这颗树,1代表根节点,对于每个节点 i i i,它的左孩子为 i × 2 i \times 2 i×2,右孩子为 i × 2 + 1 i\times 2 + 1 i×2+1,父亲节点为 i / 2 i/2 i/2最大堆和最小堆是二叉堆的形式,按照最大元素位于根节点排列的二叉堆被称为最大堆,同理按照最小元素位于根节点排列的二叉堆被称为最小堆。

二叉堆中主要的操作有查询删除插入,对于破坏堆性质的节点,可以使用上浮下沉操作进行调整。

下面的操作以最大堆为例。

上浮

不断与父节点比较,如果比父节点大就与之交换,直到不大于父节点或成为根节点为止。

void up(int p) {
    for (int i = p; i > 1 && heap[i] > heap[i / 2]; i = i / 2) {
        swap(i, i / 2);
    }
}

void swap(int p1, int p2) {
    heap[p1] += heap[p2];
    heap[p2] = heap[p1] - heap[p2];
    heap[p1] = heap[p1] - heap[p2];
}

下沉

不断与较大的子节点比较,如果比它小就与之交换,直到不小于任何子节点或成为叶子节点为止。

void down(int p) {
    for (int i = p, j = son(i); j < heap.length && heap[j] > heap[i]; i = j, j = son(i)) {
        swap(i, j);
    }
}

int son(int p) {
    return 2 * p + ((2 * p + 1 <= heap.length && heap[2 * p + 1] > heap[p]) ? 1 : 0);
}

插入

直接在数组尾部插入值,然后上浮即可。

void push(int v) {
    heap[++size] = v;
    up(size);
}

删除

可以将根节点与最后一个节点交换,使size减1,然后根节点下沉。

void pop() {
    swap(1, size--);
    down(1);
}

查询

直接返回根节点即可。

int top() {
    return heap[1];
}

代码

完整的代码为:

public class Template {

    int size;
    int[] heap;

    public Template(int _size) {
        heap = new int[_size + 1];
        size = 0;
    }

    void up(int p) {
        for (int i = p; i > 1 && heap[i] > heap[i / 2]; i = i / 2) {
            swap(i, i / 2);
        }
    }

    void swap(int p1, int p2) {
        heap[p1] += heap[p2];
        heap[p2] = heap[p1] - heap[p2];
        heap[p1] = heap[p1] - heap[p2];
    }

    void down(int p) {
        for (int i = p, j = son(i); j < size && heap[j] > heap[i]; i = j, j = son(i)) {
            swap(i, j);
        }
    }

    int son(int p) {
        return 2 * p + ((2 * p + 1 <= size && heap[2 * p + 1] > heap[p]) ? 1 : 0);
    }

    void push(int v) {
        if (size >= heap.length - 1) return;
        heap[++size] = v;
        up(size);
    }

    void pop() {
        if (size > 0) return;
        swap(1, size--);
        down(1);
    }

    int top() {
        return heap[1];
    }

    public static void main(String[] args) {
        Template template = new Template(2);
        template.push(2);
        template.push(5);
        template.pop();
        template.pop();
    }
}

参考文献:

  1. 算法学习笔记(47): 二叉堆
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值