graph LR
A[堆] --> B[最大堆 Max Heap]
A --> C[最小堆 Min Heap]
B --> B1[父节点 ≥ 子节点]
B --> B2[根节点最大]
C --> C1[父节点 ≤ 子节点]
C --> C2[根节点最小]
style A fill:#FFE4B5
style B fill:#FF6B6B
style C fill:#87CEEB
voidsiftDown(vector<int>& heap, int index, int size){ while (2 * index + 1 < size) { // 有左子节点 int left = 2 * index + 1; int right = 2 * index + 2; int largest = index; // 找出父、左子、右子中最大的 if (left < size && heap[left] > heap[largest]) { largest = left; } if (right < size && heap[right] > heap[largest]) { largest = right; } // 如果父节点最大,说明已满足堆性质 if (largest == index) { break; } swap(heap[index], heap[largest]); index = largest; } }
voidheapSort(vector<int>& nums){ int n = nums.size(); // 1. 建堆(从最后一个非叶子节点开始) for (int i = n / 2 - 1; i >= 0; --i) { heapify(nums, n, i); } // 2. 排序(依次取出堆顶) for (int i = n - 1; i > 0; --i) { swap(nums[0], nums[i]); // 堆顶与末尾交换 heapify(nums, i, 0); // 调整堆 } }
voidheapify(vector<int>& nums, int n, int i){ int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && nums[left] > nums[largest]) { largest = left; } if (right < n && nums[right] > nums[largest]) { largest = right; } if (largest != i) { swap(nums[i], nums[largest]); heapify(nums, n, largest); } }
复杂度分析
时间复杂度:O(n log n)
建堆:O(n)
n-1 次调整,每次 O(log n)
空间复杂度:O(1) 原地排序
稳定性:❌ 不稳定
堆排序的优缺点
优点
缺点
✅ 时间复杂度稳定
❌ 不稳定排序
✅ 原地排序,空间 O(1)
❌ 缓存不友好
✅ 不依赖输入分布
❌ 实际性能不如快排
堆 vs 其他数据结构
操作复杂度对比
数据结构
插入
删除最值
查看最值
查找任意元素
堆
O(log n)
O(log n)
O(1)
O(n)
无序数组
O(1)
O(n)
O(n)
O(n)
有序数组
O(n)
O(1)
O(1)
O(log n)
平衡二叉搜索树
O(log n)
O(log n)
O(log n)
O(log n)
堆的优势场景
graph LR
A[什么时候用堆?] --> B[需要频繁获取最值]
A --> C[不需要查找任意元素]
A --> D[动态数据流]
A --> E[Top K 问题]
style A fill:#FFE4B5
style B fill:#90EE90
style E fill:#87CEEB
经典应用场景
1. Top K 问题
1 2 3 4 5 6 7 8 9 10 11 12 13
// 第 K 大元素 intfindKthLargest(vector<int>& nums, int k){ priority_queue<int, vector<int>, greater<int>> minHeap; // 最小堆 for (int num : nums) { minHeap.push(num); if (minHeap.size() > k) { minHeap.pop(); } } return minHeap.top(); }
graph TD
A[选择堆类型] --> B{需要什么?}
B -->|最大值| C[最大堆]
B -->|最小值| D[最小堆]
C --> E[直接获取]
D --> F[直接获取]
style A fill:#FFE4B5
style C fill:#FF6B6B
style D fill:#87CEEB
graph TD
A[堆] --> B[基本概念]
A --> C[核心操作]
A --> D[应用场景]
A --> E[经典算法]
B --> B1[完全二叉树]
B --> B2[数组存储]
B --> B3[最大堆/最小堆]
C --> C1[上浮 O log n]
C --> C2[下沉 O log n]
C --> C3[插入 O log n]
C --> C4[删除堆顶 O log n]
C --> C5[建堆 O n]
D --> D1[Top K 问题]
D --> D2[优先队列]
D --> D3[堆排序]
D --> D4[数据流统计]
E --> E1[堆排序]
E --> E2[Dijkstra]
E --> E3[Huffman编码]
style A fill:#FFE4B5
style C fill:#87CEEB
style D fill:#90EE90