在一次面试当中,面试官问到了本身关于堆排序的一些细节,以前在整理各类高级排序的时候,有看过堆排序,然而在现场要给面试官讲解排序的原理的时候,发现本身懵逼了,因此仍是须要特意写一篇随笔来记录堆排序的整个原理和过程,这里借鉴了百度知道里头的堆排序的讲解图。面试
首先咱们要了解什么是堆排序,其排序的时间复杂度为O(nlogn),且不会由于排序的数组的数据恶化,但须要提供额外的排序内存。这里的堆当中,经常使用的数据结构就是二叉树,且是彻底二叉树。根据要排序的方式(升序,降序)能够将这个二叉树的特色定义下来,就是根节点都比左右子节点大(大根堆)或者是根节点都比左右子节点小(小根堆)。而整个堆排的过程,包括了一个建树,调整树顶的过程。二话不说,先举一个例子来讲,假定咱们要对序列{16,7,3,20,17,8}进行排序,先上咱们的流程图:数组
这是初步构建出来的树,以后,咱们从叶子节点开始从底向上遍历,调整树当中的数据,使其成为大根堆:数据结构
经过对图中画红圈的节点进行数据交换,咱们能够获得构建出来的大根堆:ui
以后咱们将根节点和最后一个叶子节点互换,而且将互换后的这个叶子节点固定住(表示这个点已经被排序好)以后调整树的时候不对该再进行调整。spa
以后的过程依次类推,最后就能够获得一个排序好的数组。code
整个流程经过图能够看的很清晰。那么接下来咱们来看看代码实现:blog
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); } }
经过代码当中的注解,结合流程图应该就能够很清晰的理解堆排序的原理和实现过程,这里就再也不进行赘述了。排序