在說明堆排序的過程前得先了解什麼是堆:java
先看下圖(來源於java數據結構和算法(第二版)):算法
堆是個徹底二叉樹,而且父節點老是大於(小於)它的孩子,所以根節點永遠是最大或者最小的元素。數組
堆排序的方法是將根節點與最後元素進行交換,並將數組容量減1,交換後最後一個元素不斷下沉直至找到合適的位置。以上圖爲例,交換過程以下:數據結構
一、將100與5交換數據結構和算法
二、將5下沉到合適的位置選出次大的元素,5和90進行比較將90提到根節點位置,而後5和60進行交換,最後5和55進行交換;3d
三、將數組容量設爲12,最後一個元素的下標爲11;blog
四、重複1和2兩個步驟直至剩下1個元素爲止。排序
此例就是按照從小到大進行排序,可將該堆稱爲最大堆,相應的若是元素需按照從大到小進行排序就須要創建最小堆。源碼
因爲給定的排序序列通常是無序的,所以首先需將序列轉換成堆。試想一下上面第二個步驟可以執行的條件是整個徹底二叉樹爲堆,而且每一個子樹都爲堆,bfc
而且下沉到正確的位置後又是一個新的堆,那麼咱們能夠構想將整個序列看成一個徹底二叉樹,而後從最後一個子樹開始不斷調用第二個算法步驟創建新堆。
對於上圖而言就是從5號節點所在的子樹開始調用下沉算法一直到根節點所在的整個樹爲止,這樣一個堆就建成了。
實際上堆排序算法也是選擇排序算法中的一種,由於它每次都從中選擇一個最大或者最小的元素依次排列到合適的位置。
時間複雜度分析:
一、數據下沉的時間複雜度與樹的高度有關,在每層中都要比較2次,所以時間複雜度爲2(h-1),有n個元素的徹底二叉樹的最大高度h爲log(n)+1;
二、每層子樹的最大個數爲,所以建堆的時間複雜度爲,子樹的總個數爲(n-3)/2
三、對於上例而言,高度h=4,比較總次數爲1*(2*3)+2*(2*2)+ 3*2=20
四、建好堆後,排序的時間複雜度爲
五、總的複雜度就是二者之和,有興趣的將兩個公式的和求出個最終結果,能夠確定的是該結果的複雜度是0(nlogn)級別的。
在具體實現時採用數組存儲,你們能夠直接看lucene中sorter類源碼的heapsort方法。