算法笔记-二叉堆

二叉堆的概念

二叉堆是一种特殊的二叉树。二叉树是每个节点只有两个子节点的树(应该都懂吧)。二叉堆分为 两 种:最大堆和最小堆,最大堆的父节点一定大于其子节点(根节点最大),最小堆的父节点小于其子节点(根节点最小)。

下面是一个二叉树:

clipboard.png

我们用一维数组将二叉树初始化,例如:我们有{1,2,3,4,5,6,7}七个数要放入堆中,第一步初始化数组的长度大于8,array[0]为null,array[1]~array[7]放入数字。

为什么array[0]为null呢?因为要用下标值找到它的子节点和父节点,比如a[1]=1,a[2]=2,a[3]。我们知道a[1]的子节点是a[2],a[3],由于是二叉树,a[k]的子节点一定是a[2k]和a[2k+1],a[k]的父节点一定是a[k/2]。花个20秒思考一下吧。

图示:

clipboard.png

将一个二叉树变成二叉堆

我以最大堆为例,最大堆的定义是:父节点的value一定要大于子节点的value。

1.子节点的value大于父节点的value的情况

此时T大于P,违反了最大堆的平衡性,所以要将T和其父节点对调
clipboard.png

但是T移动到了P的位置后,它的值依然比其父节点要大,还要上浮

clipboard.png

最终T移动到了根节点,最大堆平衡了

代码如下:



public void swim(int k) {
        while (k > 1 && less(k / 2, k)) {
            exch(k / 2, k);
            k = k / 2;
        }
    }

2. 父节点的value小于子节点的value的情况

此时,H比子节点要小,H要下沉,先比较P和S谁比较大,跟大的换位置

clipboard.png

跟S换之后,发现依然比子节点要小,还是要下浮,最后

clipboard.png

下沉的代码如下:

public void sink(int k) {
//判断是否超过数组最大长度
    while (2 * k < N) {
    //找到子节点
        int j = 2 * k;
        //两个子节点进行比较,选大的
        if (j < N && less(j, j + 1)) j++;
        //没有比子节点小,就跳出循环
        if (!less(k, j)) break;
        exch(k, j);
        k = j;
    }
}

上浮和下沉的应用(敲黑板,重点)

向数组插入value会用到上浮

每次向队尾插入一个value时,都要检查是否违反最大堆的平衡性。

clipboard.png

删除根节点时,会用到下沉

每次想删除根节点,第一步是要将跟节点与最后一个节点互换位置后,将其删除,此时最后一个节点作为根节点,一定会比子节点要小,违反平衡性,那就下浮

clipboard.png

堆排序

很简单,最大堆为例,根节点是最大的节点,每次将根节点和最后一个子节点对调位置,此时数组的最后一位即为最大,待其最大堆再次平衡时,再将根节点和最后一个子节点对调,即为排序。例如:


    数组元素为{a,b,c,d,e},假设二叉堆已经平衡,a为根节点,也就是最大的节点,将a和e对调,
    {e,b,c,d,a},数组的长度此时应该减一,将数组的前四位进行二叉堆的平衡,e肯定要下沉到相应位置,然后再将根节点和长度减一后的最后一个节点对调位置。
    
    
  • 这是我对二叉堆的理解,如有不对,欢迎指正,我会立即修改,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值