二叉堆

堆是完全二叉树,我们使用下标从1开始的数组来表示这颗树,1代表根节点,对于每个节点i,它的左孩子为i \times 2,右孩子为i\times 2 + 1,父亲节点为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): 二叉堆
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 什么是二叉堆? 二叉堆本质上是一种完全二叉树,它分为两个类型:最大堆 和 最小堆 最大堆: 任何一个父节点的值,都...
    miao8862阅读 2,187评论 0 1
  • 今天准备学习优先级阻塞队列PriorityBlockingQueue,但是它是用二叉堆实现的,所以必须先学习二叉堆...
    IT乐知阅读 1,558评论 0 0
  • 二叉堆本质上其实就是一种完全二叉树(不熟悉二叉树的可以看前面的文章:图解二叉树),它分为两种类型: 最大堆:堆中任...
    Taonce阅读 3,919评论 0 1
  • 前言 今年年初找工作的时候,参与了京东的面试,在九轮面试的第四轮中面试官出了几道算法题,其中第四道算法题用到了二叉...
    铜炉阅读 1,724评论 0 2
  • 二叉堆   二叉堆是一种特殊的堆,其实质是完全二叉树。二叉堆有两种:最大堆和最小堆。最大堆是指父节点键值总是大于或...
    ChooAcc阅读 11,599评论 4 7

友情链接更多精彩内容