核心思想
堆排序(Heap Sort)是一种基于完全二叉树结构的排序算法,利用堆的性质进行排序。其核心思想分为两个阶段:
-
构建堆:将无序数组构建成一个大顶堆(最大堆)或小顶堆(最小堆)
-
排序阶段:通过反复交换堆顶元素与末尾元素,并调整堆结构,逐步将极值元素移到有序区
算法特性
-
时间复杂度:始终为 O(n log n),无论数据是否有序
-
空间复杂度:O(1),原地排序算法
-
稳定性:不稳定(堆调整过程可能破坏相等元素的相对顺序)
-
适用场景:
-
需要保证最坏情况时间复杂度时
-
不适合小规模数据(常数因子较大)
-
内存敏感场景(原地排序)
-
算法步骤
-
Python实现
def heap_sort(arr): 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) n = len(arr) # 构建最大堆(从最后一个非叶子节点开始) for i in range(n//2 - 1, -1, -1): heapify(arr, n, i) # 逐个提取元素 for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] # 交换堆顶与末尾元素 heapify(arr, i, 0) # 调整缩小后的堆 return arr
-
C++实现
#include <iostream> #include <vector> using namespace std; void heapify(vector<int>& arr, int n, int i) { int largest = i; int l = 2 * i + 1; int r = 2 * i + 2; if (l < n && arr[l] > arr[largest]) largest = l; if (r < n && arr[r] > arr[largest]) largest = r; if (largest != i) { swap(arr[i], arr[largest]); heapify(arr, n, largest); } } void heap_sort(vector<int>& arr) { int n = arr.size(); // 构建最大堆 for (int i = n/2 - 1; i >= 0; i--) heapify(arr, n, i); // 逐个提取元素 for (int i = n-1; i > 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } }
- 将堆顶元素(最大值)与末尾元素交换
-
缩小堆范围,重新调整堆结构
-
重复直到堆大小为1
关键步骤解析 -
堆的构建(heapify):
-
时间复杂度分析:看似为O(n log n),实际通过Floyd算法优化为O(n)
-
调整过程:从当前节点向下递归调整,保证父节点始终大于子节点
-
-
排序阶段:
-
交换操作:每次将堆顶最大值交换到数组末尾
-
堆范围缩小:排序好的末尾元素不再参与后续堆调整
-
-
索引计算:
-
父节点i的左子节点:
2i + 1
-
父节点i的右子节点:
2i + 2
-
子节点i的父节点:
(i-1)//2
-
-
可视化示例
原始数组:
[4, 10, 3, 5, 1]
-
构建堆过程:
-
4 10 10 / \ / \ / \ 10 3 → 5 3 → 5 4 / \ / \ / 5 1 4 1 1
-
排序过程:
-
交换10和1 → 调整堆 → 交换5和1 → 调整堆 → ... → 最终有序
性能优化方向
-
迭代实现heapify:避免递归调用栈开销
-
堆排序将数据视为完全二叉树进行处理,既保持了选择排序的简单性,又通过堆结构将时间复杂度优化到O(n log n)级别,是理解树形结构在排序中应用的经典案例。
-
内存访问优化:利用缓存友好的访问模式
-
多叉堆:根据硬件特性调整子节点数量
-
混合排序:结合插入排序处理小规模子序列
-