阿杰,你总结的关键词很对 👍——堆排序的本质就是围绕 “维护大顶堆” + “依次取最大元素” 展开的,可以分为 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]
发表回复