• 二叉堆


    1.什么是二叉堆?

      二叉堆本质上是一种完全二叉树,它分为两个类型。

    • 最大堆—最大堆的任何一个父节点的值,都大于或等于它左、右孩子节点的值。
    • 最小堆—最小堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值。

      二叉堆的根节点叫做堆顶。

      最大堆和最小堆的特点决定了:最大堆堆顶是整个堆中的最大元素;最小堆的堆顶是整个堆中的最小元素。

    2.二叉堆的构建

      二叉堆的构建需要依靠二叉堆的自我调整

      2.1 二叉堆的自我调整

        对于二叉堆,有如下几种操作:

        • 插入节点
        • 删除节点
        • 构建二叉堆

        这几种操作都是基于堆的自我调整。所谓堆的自我调整,就是把一个不符合堆性质的完全二叉树,调整成一个堆。

        2.1.1 插入节点(以最小堆为例)

          当二叉堆插入节点时,插入位置是完全二叉树的最后一个位置。新节点与父节点比较大小,小于父节点,则新节点上浮,与父节点交换位置。依次循环比较,知道最小值到达堆顶位置,并且所有父节点都小于或等于它左、右孩子节点。

        2.1.2 删除节点

          二叉堆删除节点的过程与插入节点的过程正好相反,所删除的是处于堆顶的节点。

          需要注意的是,当删除堆顶的节点后,为了继续维持完全二叉树的结构,我们把堆的最后一个节点临时补到原本堆顶的位置,接下来,让堆顶位置的节点与它的左右孩子节点进行比较,来满足最小堆或者最大堆的特性。

        2.1.3 构建二叉堆

          构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质就是让所有非叶子节点依次下沉。

          首先,需要从最后一个非叶子节点开始,与它的左右孩子节点进行比较,并按照最大堆或者最小堆的特性依次完成节点的下沉。 

      2.2 二叉堆的代码实现

        首先,我们要明确一点,二叉堆虽然是一个完全二叉树,但是它的存储方式并不是链式存储,二是顺序存储。换句话说,二叉堆的所有节点都存储在数组中。

        在数组中,在没有左右指针的情况下,如何定位一个父节点的左孩子和右孩子呢?

        假设父节点的下标是parent,那么它左孩子的下标就是2 * parent + 1;右孩子的下标就是2 * parent +2。

        简单的代码实现如下:

     1 package com.algorithm.test;
     2 
     3 import java.util.Arrays;
     4 
     5 /**
     6  * @Author Jack丶WeTa
     7  * @Date 2020/7/30 11:13
     8  * @Description 二叉堆的代码实现
     9  */
    10 public class HeapTest {
    11 
    12     /**
    13      * "上浮"调整
    14      * @param array 待调整的堆
    15      */
    16     public static void upAdjust(int[] array){
    17         int childIndex = array.length - 1;
    18         int parentIndex = (array.length - 1) / 2;
    19         //temp保存插入的叶子节点的值,用于最后的赋值
    20         int temp = array[childIndex];
    21         while (childIndex > 0 && temp < array[parentIndex]) {
    22             //无须真正交换,单向赋值即可
    23             array[childIndex] = array[parentIndex];
    24             childIndex = parentIndex;
    25             parentIndex = (parentIndex - 1) / 2;
    26         }
    27         array[childIndex] = temp;
    28     }
    29 
    30     /**
    31      * "下称调整"
    32      * @param array         待调整的堆
    33      * @param parentIndex   要“下称”的父节点
    34      * @param length        堆的有效大小
    35      */
    36     public static void downAdjust(int[] array, int parentIndex, int length){
    37         //temp保存父节点的值,用于最后赋值
    38         int temp = array[parentIndex];
    39         int childIndex = 2 * parentIndex + 1;
    40         while (childIndex < length) {
    41             //如果有右孩子,且右孩子小于左孩子的值则定位到右孩子
    42             if (childIndex + 1 < length && array[childIndex+1] < array[childIndex])
    43                 childIndex++;
    44             //如果父节点小于任何一个孩子的值,则直接跳出
    45             if (temp < array[childIndex])
    46                 break;
    47 
    48             //无须真正交换,单向赋值即可
    49             array[parentIndex] = array[childIndex];
    50             parentIndex = childIndex;
    51             childIndex = 2 * childIndex + 1;
    52         }
    53         array[parentIndex] = temp;
    54     }
    55 
    56     /**
    57      * 构建堆
    58      * @param array 待调整的堆
    59      */
    60     public static void buildHeap(int[] array){
    61         //从最后一个非叶子节点开始,依次做“下沉”调整
    62         for (int i = (array.length - 2) / 2; i >= 0; i--){
    63             downAdjust(array, i, array.length);
    64         }
    65     }
    66 
    67     public static void main(String[] args) {
    68         int[] array = new int[]{1,3,2,6,5,7,8,9,10,0};
    69         upAdjust(array);
    70         System.out.println(Arrays.toString(array));
    71 
    72         array = new int[]{7,1,3,10,5,2,8,9,6};
    73         buildHeap(array);
    74         System.out.println(Arrays.toString(array));
    75     }
    76 }

      堆的插入操作是单一节点的“上浮”,堆的删除操作是单一节点的“下沉”,这两个操作的平均交换次数都是堆高度的一半,所以时间复杂度是0(logn),至于堆的构建,则是O(n)。

  • 相关阅读:
    用protobuf编译时报错:protoc: error while loading shared libraries: libprotoc.so.9: cannot open shared object file: No such file or directory 的解决方法
    编译dubbo2.5.4时遇到的问题及解决
    在ubuntu16.04 下安装haproxy 1.5.11 做tcp负载均衡
    [原创] zabbix学习之旅七:如何远程操作被监控机器
    [原创] zabbix学习之旅五:如何快速搭建一个报警系统
    [原创] zabbix学习之旅四:mail客户端安装
    [原创] zabbix学习之旅三:agent安装
    [原创] zabbix学习之旅二:yum安装
    scipy 中关于排列组合的函数
    极大似然估计 (二)
  • 原文地址:https://www.cnblogs.com/JackWeTa/p/13402974.html
Copyright © 2020-2023  润新知