堆排序是利用二叉堆這一數據結構實現的選擇排序,時間複雜度穩定在 O(n log n),空間複雜度 O(1),是不穩定排序中效能最可靠的算法之一。本文從堆的性質、建堆與調整邏輯、排序流程圖解、複雜度分析到 Java 完整實現,全方位剖析堆排序。
初始: 89
/ \
-7 999
/ \ / \
-89 7 0 -888
/ \
7 -7
調整後大頂堆: 999
/ \
89 7
/ \ / \
7 -7 0 -888
/ \
-89 7
每輪將當前最大值移至有序區末尾,無序區縮小,最終得到升序數組:[-888, -89, -7, -7, 0, 7, 7, 89, 999]
適用場景:數據量極大(百萬級+),避免快速排序遞歸導致棧溢出;嵌入式系統記憶體受限環境。
public class HeapSort {
public static void sort(int[] arr) {
int n = arr.length;
// 1. 建立大頂堆:從最後一個非葉子節點開始下沉
for (int i = (n - 2) / 2; i >= 0; i--) {
sink(arr, i, n);
}
// 2. 逐輪提取最大值
while (n > 1) {
swap(arr, 0, --n); // 堆頂與當前堆尾交換
sink(arr, 0, n); // 新堆頂下沉
}
}
/** 下沉調整:將 idx 位置元素在 size 範圍內下沉到合適位置 */
private static void sink(int[] arr, int idx, int size) {
while (true) {
int left = 2 * idx + 1;
int right = 2 * idx + 2;
int largest = idx;
if (left < size && arr[left] > arr[largest]) largest = left;
if (right < size && arr[right] > arr[largest]) largest = right;
if (largest == idx) break; // 已滿足堆性質
swap(arr, idx, largest);
idx = largest; // 繼續向下調整
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 測試
public static void main(String[] args) {
int[] data = {89, -7, 999, -89, 7, 0, -888, 7, -7};
sort(data);
System.out.println(Arrays.toString(data));
// [-888, -89, -7, -7, 0, 7, 7, 89, 999]
}
}
堆排序以「完全二叉樹隱式存儲 + 下沉調整」實現原地 O(n log n) 排序。掌握 sink 核心邏輯與建堆的線性時間證明,是演算法面試與高效工程實踐的必修課。實際項目中,優先考慮 JDK Arrays.sort()(雙軸快排+TimSort),但在特定約束下(嵌入式、實時系統、超大數據流),手寫堆排序不可替代。