阿杰,你总结的关键词很对 👍——堆排序的本质就是围绕 “维护大顶堆” + “依次取最大元素” 展开的,可以分为 4 个阶段:


📌 堆排序的本质理解

1. 建堆(Heapify)

  • 把一个无序数组调整为 大顶堆(或小顶堆)。
  • 大顶堆的性质:父节点 ≥ 子节点。
  • 建堆过程就是自底向上调用 heapify(),保证整个数组满足堆的性质。
  • 复杂度 O(n)

👉 直观理解:
就像把一堆杂乱的球放进一个“最大优先”的容器里,保证每次取出的球都是最大的。


2. 交换(Swap)

  • 堆顶元素是堆中最大的元素。
  • 把堆顶元素与当前堆的最后一个元素交换。
  • 此时,最大元素被“移出堆”,放到数组的正确位置(末尾)。

👉 直观理解:
把“最大球”拿出来,放到结果箱子里。


3. 装箱(Shrink)

  • 刚才取走了一个元素,相当于堆的规模减 1。
  • 现在需要对 新的堆顶元素 进行 heapify(),恢复大顶堆性质。

👉 直观理解:
堆被拿掉一个球后有点乱,需要“重新整理”。


4. 重复(Repeat)

  • 重复 交换 + 装箱 的过程,直到堆里只剩下一个元素。
  • 最终,数组变成从小到大有序的序列。

👉 直观理解:
不断“取出最大球 → 放进箱子 → 整理堆”,直到所有球都被放好。


🔑 总结口诀

堆排序 = 建堆 → 交换堆顶与尾 → 调整堆 → 重复

  • 建堆:一次性 O(n)
  • 交换 + 调整:执行 (n-1) 次,每次 O(log n)
  • 总复杂度:O(n log n),原地排序,不需要额外空间

📖 Python 简单实现



def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1
    r = 2 * i + 2

    if l < n and arr[l] > arr[largest]:
        largest = l
    if r < n and arr[r] > arr[largest]:
        largest = r

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)

    # 1. 建堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 2. 交换 + 装箱 + 重复
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]  # 交换堆顶和末尾
        heapify(arr, i, 0)  # 调整堆

    return arr

print(heap_sort([3, 9, 2, 1, 4, 5]))
# 输出: [1, 2, 3, 4, 5, 9]