• 常用数据结构算法 : 堆排序


      在一次面试当中,面试官问到了自己关于堆排序的一些细节,之前在整理各种高级排序的时候,有看过堆排序,然而在现场要给面试官讲解排序的原理的时候,发现自己懵逼了,所以还是需要特地写一篇随笔来记录堆排序的整个原理和过程,这里借鉴了百度知道里头的堆排序的讲解图。

      首先我们要了解什么是堆排序,其排序的时间复杂度为O(nlogn),且不会因为排序的数组的数据恶化,但需要提供额外的排序内存。这里的堆当中,常用的数据结构就是二叉树,且是完全二叉树。根据要排序的方式(升序,降序)可以将这个二叉树的特点定义下来,就是根节点都比左右子节点大(大根堆)或者是根节点都比左右子节点小(小根堆)。而整个堆排的过程,包括了一个建树,调整树顶的过程。二话不说,先举一个例子来说,假定我们要对序列{16,7,3,20,17,8}进行排序,先上我们的流程图:

    这是初步构建出来的树,之后,我们从叶子节点开始从底向上遍历,调整树当中的数据,使其成为大根堆:

    通过对图中画红圈的节点进行数据交换,我们可以得到构建出来的大根堆:

    之后我们将根节点和最后一个叶子节点互换,并且将互换后的这个叶子节点固定住(表示这个点已经被排序好)之后调整树的时候不对该再进行调整。

    之后的过程依次类推,最后就可以得到一个排序好的数组。

    整个流程通过图可以看的很清晰。那么接下来我们来看看代码实现:

    public class testHeapSort {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[] input={2,3,5,2,3,6,7,4,6};
            HeapSort(input);
            for(int tmp:input)
                System.out.print(tmp+" ");
        }
        
        //堆排序
        public static void HeapSort(int array[])
        {
            buildTheTree(array);
            
            //从数组当中最后一个位置开始固定,一次固定到头,即可得到升序数组
            for(int i=array.length-1;i>=1;i--)
            {
                //根和当前最后的叶子节点交换
                int tmp=array[0];
                array[0]=array[i];
                array[i]=tmp;
                
                //调整堆
                maxify(array, i, 0);
            }
        }
        
        //第一次建树
        public static void buildTheTree(int array[])
        {
            //因为是从叶子节点开始从底向上的调整,所以起点为数组长度的2分之一
            int half=array.length/2;
            
            for(int i=half;i>=0;i--)
            {
                maxify(array, array.length, i);
            }
            
        }
        
        //调整树的方法,大顶堆
        public static void maxify(int array[],int size,int i)
        {
            //左子节点
            int left=2*i+1;
            //右子节点
            int right=2*i+2;
            
            //找出当前根节点、其左子节点、右子节点最大的节点作为根节点
            int large=i;
            if(left<size && array[left]>array[i])large=left;
            if(right<size && array[right]>array[large])large=right;
            
            //如果再上边查找过程当中,根节点就是最大的节点,那么不需要再去调整树,因为这是一个从下往上调整的过程
            //所以当前节点以下的树已经满足大根堆的要求,直接返回
            if(large==i)return;
            
            //如果需要当前根节点和子节点互换,则互换过去的子节点再一次调整
            int tmp=array[large];
            array[large]=array[i];
            array[i]=tmp;
            //互换后调整。
            maxify(array, size, large);
        }
    }

    通过代码当中的注解,结合流程图应该就可以很清晰的理解堆排序的原理和实现过程,这里就不再进行赘述了。

  • 相关阅读:
    day67——前后端传输数据的编码格式、ajax传json数据/传文件、批量插入
    day66——choices参数、MTV/MVC模型、三种创建多对多的方式、AJAX
    day65——聚合函数、分组查询、F与Q查询、django开事务、orm查询优化
    dayⅢ、基本数据类型+运算符作业
    dayⅡ:编程语言+变量+垃圾回收制
    dayⅡ:变量作业
    dayⅠ:计算机基础知识
    ⅩⅥ:无参装饰器
    ⅩⅤ:作业
    ⅩⅤ:名称空间与作用域
  • 原文地址:https://www.cnblogs.com/WellHold/p/7561529.html
Copyright © 2020-2023  润新知