每天学一个算法--堆排序(Heap Sort)

📘 堆排序(Heap Sort)

1. 问题定义

给定数组 (A[1...n]),要求:

A\[1\]≤A\[2\]≤⋯≤A\[n\]\]\[ A\[1\] \\le A\[2\] \\le \\dots \\le A\[n\] \]\[A\[1\]≤A\[2\]≤⋯≤A\[n\]

2. 核心思想

堆排序的核心不是分治,而是:

利用"堆(Heap)这种特殊数据结构"进行排序

3. 核心术语

3.1 堆(Heap)

定义:

一种完全二叉树,满足:

👉 堆性质(Heap Property)

🔹 最大堆(Max Heap)

A\[parent\]≥A\[child\]\]\[ A\[parent\] \\ge A\[child\] \]\[A\[parent\]≥A\[child\]

👉 根节点是最大值


🔹 最小堆(Min Heap)

A\[parent\]≤A\[child\]\]\[ A\[parent\] \\le A\[child\] \]\[A\[parent\]≤A\[child\]

👉 根节点是最小值


3.2 完全二叉树(Complete Binary Tree)

定义:

  • 除最后一层外,每层都满
  • 最后一层从左到右填充

为什么重要?

👉 可以用数组表示


3.3 数组表示(关键)

对于节点 (i):

  • 左子节点:(2i)(2i)(2i)
  • 右子节点:(2i+1)(2i + 1)(2i+1)
  • 父节点:(⌊i/2⌋)(\lfloor i/2 \rfloor)(⌊i/2⌋)

3.4 堆化(Heapify)

定义:

调整某个节点,使其满足堆性质


本质:

把"不合法的节点"向下调整


4. 堆排序整体流程


Step 1:建堆(Build Heap)

将数组变成最大堆


Step 2:排序

重复:

  1. 交换堆顶和末尾元素
  2. 缩小堆范围
  3. 对根节点执行 heapify

一句话总结

每次取出最大值,放到数组末尾


5. 算法结构


5.1 主函数

text 复制代码
HeapSort(A):
    BuildMaxHeap(A)

    for i = n downto 2:
        swap(A[1], A[i])
        heap_size -= 1
        Heapify(A, 1)

5.2 Heapify

text 复制代码
Heapify(A, i):
    largest = i

    if left child > A[i]:
        largest = left

    if right child > A[largest]:
        largest = right

    if largest ≠ i:
        swap(A[i], A[largest])
        Heapify(A, largest)

6. 核心机制(教学重点)


6.1 为什么堆能排序?

因为:

👉 最大堆的根节点是当前最大值


6.2 每一步发生了什么?

text 复制代码
[堆] → 取最大值 → 放到末尾 → 剩下继续堆化

6.3 本质过程

不是"排序",而是:

不断从结构中"取最大值"


7. 建堆过程(必须讲)


7.1 为什么从 n/2 开始?

因为:

  • 叶子节点本身已经满足堆性质
  • 只需要调整非叶子节点

7.2 建堆代码

text 复制代码
BuildMaxHeap(A):
    for i = n/2 downto 1:
        Heapify(A, i)

7.3 时间复杂度(关键点)

👉 不是 (O(n \log n))

而是:

O(n)\]\[ O(n) \]\[O(n)


为什么?

  • 底层节点多,但调整成本低
  • 上层节点少,但调整成本高

整体为线性复杂度


8. 示例(必须讲)


初始数组

text 复制代码
[4, 10, 3, 5, 1]

建堆

text 复制代码
      10
     /  \
    5    3
   / \
  4   1

排序过程

Step 1:

text 复制代码
swap(10,1)
→ [1,5,3,4,10]

heapify:

text 复制代码
→ [5,4,3,1,10]

继续重复,最终:

text 复制代码
[1,3,4,5,10]

9. 时间复杂度


9.1 组成

  • 建堆:(O(n))
  • 每次 heapify:(O(\log n))
  • 共 (n) 次

9.2 总复杂度

O(nlog⁡n)\]\[ O(n \\log n) \]\[O(nlogn)


9.3 特点

👉 无最坏退化


10. 空间复杂度


O(1)\]\[ O(1) \]\[O(1)

👉 原地排序


11. 稳定性


❌ 不稳定

因为存在跨层交换


12. 与前两个算法对比(关键)

算法 核心机制 空间 稳定性
快排 partition 原地
归并 merge O(n)
堆排 heap 原地

13. 常见错误


❌ 错误1:搞错数组下标关系

必须记住:

text 复制代码
left = 2i
right = 2i+1

❌ 错误2:Heapify写错

只调整一次不够

👉 必须递归


❌ 错误3:建堆方向错

必须从:

text 复制代码
n/2 → 1

14. 关键结论


  1. 堆排序核心是 heapify
  2. 最大堆保证快速取最大值
  3. 时间复杂度稳定 (n log n)
  4. 空间复杂度最优(O(1))

15. 最小教学总结

堆排序的本质不是"比较排序",而是:

用一个结构(堆)不断取出最大元素

相关推荐
programhelp_1 小时前
ZipRecruiter CodeSignal OA 2026|最新真题分享 + 速通攻略
数据结构·经验分享·算法·面试
绿豆人2 小时前
go语言的Reflect包
java·开发语言·数据结构
liuyao_xianhui2 小时前
map和set_C++
java·开发语言·数据结构·c++·算法·宽度优先
墨^O^2 小时前
C++ Memory Order 完全指南:从 relaxed 到 seq_cst,深入理解无锁编程与 happens-before
linux·开发语言·c++·笔记·学习·算法·缓存
6Hzlia2 小时前
【Hot 100 刷题计划】 LeetCode 51. N 皇后 | C++ 回溯算法&状态数组
c++·算法·leetcode
脱氧核糖核酸__2 小时前
LeetCode热题100——41.缺失的第一个正数(题解+答案+要点)
数据结构·c++·算法·leetcode·哈希算法
脱氧核糖核酸__2 小时前
LeetCode热题100——73.矩阵置零(题目+题解+答案)
c++·算法·leetcode·矩阵
Mr_Xuhhh3 小时前
深入理解单链表的递归反转:从原理到实现
算法·leetcode·职场和发展
智者知已应修善业3 小时前
【51单片机数码管+蜂鸣器的使用】2023-6-14
c++·经验分享·笔记·算法·51单片机