zoukankan      html  css  js  c++  java
  • 二叉堆

          二叉堆的本质是一种完全二叉树,它分为两种类型,分别是最大堆和最小堆。

          最大堆的任何一个父节点的值,都大于或者等于它的左右孩子节点的值;最小堆的任何一个父节点的值都小于或等于它的左右孩子结点的值。二叉堆的根结点叫做堆顶。由其性质可以知道,最大堆的堆顶元素是整个堆得最大值,最小堆得的元素是整个堆得最小值。

    二叉堆的自我调整

    二叉堆的主要操作:

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

    下面以最小堆为例,来看看他的调整过程。

    插入节点:

    当插入一个节点时,插入的位置是完全二叉树的最后一个位置。例如要插入的新节点为0,为了保持最小堆的特点,新节点0比父节点6小,于是让节点0 做“上浮”操作,与父节点交换位置。后面也是这样依次操作。

     删除节点:

           二叉堆删除节点的过程与插入节点的过程相反,删除的是堆顶的节点。假如要删除的元素是堆顶的元素1,这时为了保持完全二叉树的结构,此时先将堆的最后一个节点9临时补到原来的堆顶的位置,然后让节点9与其左、右孩子比较,如果左、右孩子节点中的最小的一个(本图是2)节点比其小,就让其 做“下沉” 操作。后面也是这样依次操作。

     

     构建二叉堆

          就是把一个无序的完全二叉树调整为二叉堆,其本质是让所有的非叶子节点依次“下沉”。(首先应该从最后一个非叶子节点开始)

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

    代码实现(最小堆):

           二叉堆虽然也是一个完全二叉树,但是他的存储方式确不是链式结构,而是顺序存储。他所有的节点都是存储在数组中的。

        他的节点确定规则是:令父节点的下标为parent孩子下标为child,则其左孩子下标为parent*2+1,其右孩子下标为parent*2+2。那么如果已知其左孩子下标,则其父节点下标为(child-1)/2。右孩子也是同理。

     /**
         * 上浮调整
         * @param array   待调整的堆
         */
        private static void upAdjust(int[] array) {
            int childIndex = array.length - 1;
            int parentIndex = (childIndex - 1)/2;
            int temp = array[childIndex];   //temp保存插入的叶子结点值,用于最后的赋值
            while (childIndex > 0 && temp < array[parentIndex]){
    //            无需真正交换,单向赋值
                array[childIndex] = array[parentIndex];
                childIndex = parentIndex;
                parentIndex = (childIndex - 1)/2;
            }
            array[childIndex] = temp;
        }
    
        /**
         *构建堆
         * @param array
         */
        private static void buildHeap(int[] array) {
    
    //        从最后一个非叶子结点开始,依次做下沉操作
            for (int i = (array.length - 2)/2; i >= 0 ; i--) {
                downAdjust(array,i,array.length);
            }
        }
    
        /**
         * 下沉调整
         * @param array  待调整堆
         * @param parentIndex  父节点
         * @param length  数组长队
         */
        private static void downAdjust(int[] array, int parentIndex, int length) {
            //保存父节点值
            int temp = array[parentIndex];
            //左孩子的下标
            int childIndex = 2*parentIndex + 1;
            while (childIndex < length){
                //如果有右孩子并且,右孩子的值比左孩子还小的话,定位到右孩子
                if(childIndex + 1 < length && array[childIndex+1] < array[childIndex] ){
                    childIndex++;
                }
                if(temp <= array[childIndex])
                    break;  //父节点小于任意一个子节点
                    array[parentIndex] = array[childIndex];
                    parentIndex = childIndex;
                    childIndex = 2*parentIndex + 1;
            }
            array[parentIndex] = temp;
    
        }

     最大堆只需要在上面基础上进行稍微的改动即可。

  • 相关阅读:
    IOS开发学习 IDE环境搭建教程
    [转]CSS技巧:无懈可击的CSS圆角技术
    ASP.NET2.0 ObjectDataSource的使用详解(2) (转)
    ASP.NET 2.0 数据绑定概述(谭振林)
    分页储存过程
    ASP.NET2.0 ObjectDataSource的使用详解(1) (转)
    使用Gridview和ObjectDataSource轻松实现自定义分页
    FckEditor中文配置手册详细说明
    Head First IL中间语言实例深入经典诠释(转)
    C#的内存管理:堆栈、托管堆与指针 (转)
  • 原文地址:https://www.cnblogs.com/128-cdy/p/13411338.html
Copyright © 2011-2022 走看看