动态

详情 返回 返回

堆排序算法介紹 - 动态 详情

堆排序(Heap Sort)完整指南

維度 內容
核心思想 用數組模擬完全二叉堆,反覆彈出最大值(或最小值)完成排序
平均複雜度 O(n log n)
最壞複雜度 O(n log n) (無退化)
額外空間 O(1) (原地)
穩定性 (相等元素可能翻轉)
實現難度 ★★☆ (約 30 行代碼)

1 堆基礎速覽

術語 解釋
最大堆 父節點 ≥ 子節點,根為全局最大
存儲方式 一維數組下標 i 的左右子分別為 2i+12i+2
高度 h = floor(log2(n)),約 lg n

2 算法步驟(升序,最大堆)

  1. 建堆(heapify):把無序數組原地變成最大堆

    • 自底向上 sift-down,複雜度 O(n)
  2. 排序階段
    a. 交換堆頂 a[0] 與末尾 a[i]
    b. 堆大小 -1
    c. 對新堆頂 sift-down 恢復堆序
    重複 n-1 次即得升序

3 代碼實現(C++17,整數模板)

#include <vector>
#include <algorithm>

template <class T>
inline void siftDown(T* a, int n, int root) {
    while (true) {
        int l = 2 * root + 1;
        int r = l + 1;
        int largest = root;
        if (l < n && a[l] > a[largest]) largest = l;
        if (r < n && a[r] > a[largest]) largest = r;
        if (largest == root) break;
        std::swap(a[root], a[largest]);
        root = largest;
    }
}

template <class T>
void heapSort(T* a, int n) {
    // 1. 建最大堆
    for (int i = n / 2 - 1; i >= 0; --i)
        siftDown(a, n, i);
    // 2. 依次提取最大元
    for (int i = n - 1; i > 0; --i) {
        std::swap(a[0], a[i]);   // 當前最大沉底
        siftDown(a, i, 0);       // 恢復堆
    }
}

4 複雜度分析

階段 比較次數 説明
建堆 ≤ 2n 自底向上 sift-down
排序 n log n 每次 sift-down 深度 ≤ log n
O(n log n) 最壞、平均、最好一致

5 穩定性 & 順序敏感性

  • 不穩定:交換堆頂與末尾時可能改變相等元素相對順序
  • 若需穩定 → 改用 歸併排序 或記錄原始下標

6 常考優化

技巧 效果
循環展開 + 分支預測 提速 1015%
三值取中(median-of-3) 減小建堆常數
批量建堆 std::make_heap 已集成 Floyd 算法

7 與其他 O(n log n) 算法對比

算法 | 額外空間 | 最壞 |穩定性| 特點
快速排序 | O(log n) | O(n²) 否 | 平均最快,但最壞退化
歸併排序 | O(n) | O(n log n) | ✅ 穩定,需緩衝區
堆排序 | O(1) | O(n log n) | 否 | 空間潔癖,無退化


8 應用場景

✅ 內存受限(嵌入式、單片機)

✅ 需要硬實時(最壞確定)

✅ 作為 內省排序 (std::sort) 的 fallback

❌ 對 穩定性 有要求

❌ 數據 近乎有序(此時插入更快)


9 一句話總結

堆排序 = 原地建堆 + 反覆彈出最大值;

保證 O(n log n) 最壞且 O(1) 空間,是“空間潔癖”與“硬實時”場景的首選。

user avatar crossoverjie 头像 idiomeo 头像 liberhome 头像 syntaxerror 头像 dadebinglin 头像 aihejiudejiqiren_bjjawt 头像 hello_64e0ef2dbbb8f 头像 niandou 头像
点赞 8 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.