基本思路
- 1.若array[0,…,n-1]表示一顆完全二叉樹的順序存儲模式,則雙親節點指針和孩子結點指針之間的內在關係如下:
任意一節點指針 i:
父節點:i==0 ? null : (i-1)/2
左孩子:2*i + 1
右孩子:2*i + 2
- 2.堆得定義
n個關鍵字序列array[0,...,n-1],當且僅當滿足下列要求:(0 <= i <= (n-1)/2)
① array[i] <= array[2*i + 1] 且 array[i] <= array[2*i + 2]; 稱爲小根堆;
② array[i] >= array[2*i + 1] 且 array[i] >= array[2*i + 2]; 稱爲大根堆;
- 3.建立大頂堆 n個節點的完全二叉樹array[0,…,n-1],最後一個節點n-1是第(n-1-1)/2個節點的孩子。對第(n-1-1)/2個節點爲根的子樹調整,使該子樹稱爲堆。
對於大根堆,調整方法爲:若【根節點的關鍵字】小於【左右子女中關鍵字較大者】,則交換。
之後向前依次對各節點((n-2)/2 - 1)~ 0爲根的子樹進行調整,看該節點值是否大於其左右子節點的值,若不是,將左右子節點中較大值與之交換,交換後可能會破壞下一級堆,於是繼續採用上述方法構建下一級的堆,直到以該節點爲根的子樹構成堆爲止。
反覆利用上述調整堆的方法建堆,直到根節點。
- 4.堆排序(大頂堆)
①將存放在array[0,...,n-1]中的n個元素建成初始堆;
②將堆頂元素與堆底元素進行交換,則序列的最大值即已放到正確的位置;
③將數組中array[0,...,n-1]前n-1個元素再次形成大根堆,再重複第②③步,直到堆中僅剩下一個元素爲止。
代碼實現
/**
* 大頂堆排序
* @param array
*/
public static void maxHeapSort(int[] array) {
int i;
int len = array.length;
// 構建大頂堆
for (i = len / 2 - 1; i >= 0; i--) {
adjustMaxHeap(array, i, len);
}
// 堆頂是最大值,交換堆頂和最後一個數,再重新調整最大堆,下一次循環 i--
for (i = len - 1; i >= 0; i--) {
int temp = array[0];
array[0] = array[i];
array[i] = temp;
adjustMaxHeap(array, 0, i);
}
System.out.println(Arrays.toString(array));
}
private static void adjustMaxHeap(int[] a, int pos, int len) {
int temp;
int child;
for (temp = a[pos]; 2 * pos + 1 < len; pos = child) {
// 數組從0開始,r(i)>=r(2i) r(i)>=r(2i+1) 對應 pos => 2 * pos + 1 和 2 * pos +2
child = 2 * pos + 1;
// 有右孩子,且右孩子數值更大
if (child + 1 < len && a[child] < a[child + 1]) {
child++;
}
// 最大的孩子大於根節點
if (a[child] > temp) {
a[pos] = a[child];
} else {
break;
}
}
a[pos] = temp;
}
時間複雜度和空間複雜度
時間複雜度:建堆:o(n),每次調整o(log n),故最好、最壞、平均情況下:o(n*logn)。