堆排序是一種樹形選擇排序,是對直接選擇排序的有效改進。html
具備n個元素的序列(h1,h2,...,hn),當且僅當知足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,...,n/2)時稱之爲堆。在這裏只討論知足前者條件的堆。由堆的定義能夠看出,堆頂元素(即第一個元素)必爲最大項(大頂堆)。徹底二 叉樹能夠很直觀地表示堆的結構。堆頂爲根,其它爲左子樹、右子樹。java
初始時把要排序的數的序列看做是一棵順序存儲的二叉樹,調整它們的存儲序,使之成爲一個堆,這時堆的根節點的數最大。而後將根節點與堆的最後一個節點交換。而後對前面(n-1)個數從新調整使之成爲堆。依此類推,直到只有兩個節點的堆,並對它們做交換,最後獲得有n個節點的有序序列。從算法描述來看,堆排序須要兩個過程,一是創建堆,二是堆頂與堆的最後一個元素交換位置。因此堆排序有兩個函數組成。一是建堆的滲透函數,二是反覆調用滲透函數實現排序的函數。算法
/**
* 創建堆
* @param a 待建的數組
* @param lastIndex 須要創建的數組的最後一個元素(控制須要創建堆的長度)
*/
private void buildMaxHeap(int[] a, int lastIndex){
// 從lastIndex處節點(最後一個節點)的父節點開始
for(int i = (lastIndex-1)/2; i >=0 ; i--){
// k保存正在判斷的節點
int k=i;
// 若是當前的節點的子節點存在
while (k*2+1<=lastIndex){
// biggerIndex 爲最大值的索引,先將其賦值爲左子節點
int biggerIndex = k*2+1;
// 若是存在右子節點,則須要比較其大小
if(biggerIndex < lastIndex){
// biggerIndex始終爲最大的子節點。
if(a[biggerIndex + 1] > a[biggerIndex]){
biggerIndex++;
}
}
// 若是k節點的值小於其較大的子節點的值,則須要交換他們
if(a[biggerIndex] > a[k]){
swap(a, biggerIndex, k);
// 交換後的左子節點,、
// 有可能小於他本身的子節點,
// 因此須要從新進行比較排序,
// 保證最小值在下面的節點
k = biggerIndex;
} else {
break;
}
}
}
}
/**
* 交換
*/
private void swap(int[] a, int i, int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public void heapSort(int[] a){
for(int i=0; i<a.length-1; i++){
buildMaxHeap(a, a.length-1-i);
swap(a, 0, a.length-1-i);
}
}
@Test
public void heapTest(){
int[] a={7,5,3,2,9,10,8,4,6,1};
heapSort(a);
System.out.println(Arrays.toString(a));
}
複製代碼
參考:
必須知道的八大種排序算法【java實現】(二) 選擇排序,插入排序,希爾算法【詳解】
數據結構常見的八大排序算法(詳細整理)數組