在一次面試當中,面試官問到了本身關於堆排序的一些細節,以前在整理各類高級排序的時候,有看過堆排序,然而在現場要給面試官講解排序的原理的時候,發現本身懵逼了,因此仍是須要特意寫一篇隨筆來記錄堆排序的整個原理和過程,這裏借鑑了百度知道里頭的堆排序的講解圖。面試
首先咱們要了解什麼是堆排序,其排序的時間複雜度爲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); } }
經過代碼當中的註解,結合流程圖應該就能夠很清晰的理解堆排序的原理和實現過程,這裏就再也不進行贅述了。排序