你问的是数据结构里的“堆”,并想深入理解它 结构原理 + 操作逻辑 + 排序实现——这正是面试、刷题、项目中常考的重点数据结构之一,尤其在优先队列、堆排序、TopK 等场景频繁出现。
下面我来系统讲透堆(Heap)👇
🧠 一、什么是“堆”(Heap)
堆是一棵特殊的完全二叉树(Complete Binary Tree),满足以下性质:
- 大顶堆(Max-Heap):父节点 ≥ 子节点
- 小顶堆(Min-Heap):父节点 ≤ 子节点
💡 完全二叉树 → 除最后一层外都是满的,最后一层从左到右填满
✅ 二、堆的存储结构:用数组实现
虽然是二叉树,但实际堆都用数组来实现!
数组下标和节点关系:
节点下标 | 左子节点 | 右子节点 | 父节点 |
---|---|---|---|
i | 2i + 1 | 2i + 2 | (i - 1)/2 |
🚀 三、堆的基本操作
🔼 插入元素(heapify up)
- 把新元素插在数组末尾;
- 与父节点比较,若违反堆性质就向上交换;
- 直到恢复堆结构。
时间复杂度:O(log n)
🔽 删除堆顶(heapify down)
- 删除堆顶(数组第一个元素);
- 用最后一个元素顶上去;
- 与左右孩子比较并下沉,直到满足堆性质。
时间复杂度:O(log n)
✍️ 四、代码演示(手动实现最小堆)
#include <vector>
#include <iostream>
class MinHeap {
std::vector<int> data;
void heapify_up(int i) {
while (i > 0 && data[i] < data[(i - 1) / 2]) {
std::swap(data[i], data[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
void heapify_down(int i) {
int n = data.size();
while (true) {
int smallest = i;
int l = 2 * i + 1, r = 2 * i + 2;
if (l < n && data[l] < data[smallest]) smallest = l;
if (r < n && data[r] < data[smallest]) smallest = r;
if (smallest == i) break;
std::swap(data[i], data[smallest]);
i = smallest;
}
}
public:
void push(int val) {
data.push_back(val);
heapify_up(data.size() - 1);
}
void pop() {
std::swap(data[0], data.back());
data.pop_back();
heapify_down(0);
}
int top() const { return data[0]; }
bool empty() const { return data.empty(); }
};
📦 五、堆排序(Heap Sort)
堆排序 = 先建堆 + 反复取堆顶 + 调整堆结构
✨ 思路:
- 将数组建立为 最大堆(build heap)
- 交换堆顶与末尾元素
- 将剩余部分继续调整为最大堆
- 重复直到排序完成
✅ 时间复杂度:
操作 | 时间复杂度 |
---|---|
建堆 | O(n) |
每次调整堆 | O(log n) |
总体排序复杂度 | O(n log n) |
📌 特点:
- 原地排序,不需要额外空间(O(1))
- 非稳定排序
- 最坏、最好、平均时间复杂度都是 O(n log n)
🔁 堆排序代码示例(从数组中排序)
#include <iostream>
#include <vector>
#include <algorithm>
void heapify(std::vector<int>& arr, int n, int i) {
int largest = i, l = 2*i + 1, 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) {
std::swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heap_sort(std::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--) {
std::swap(arr[0], arr[i]); // 把最大值放最后
heapify(arr, i, 0); // 剩下部分建堆
}
}
✅ 面试总结模板(可背):
堆是一种满足“父节点 ≥ 子节点(或 ≤)”的完全二叉树,通常用数组实现,支持高效地插入元素和获取最大/最小值,时间复杂度是 O(log n)。堆在 C++ 中广泛应用于优先队列、TopK 问题、任务调度等场景,堆排序基于最大堆实现,整体时间复杂度为 O(n log n)。