堆详解及C语言实现
堆结构与最大堆详解:从原理到C语言实现
1. 堆结构概述
1.1 定义与性质
堆(Heap)是一种特殊的完全二叉树数据结构,满足以下性质:
- 结构性:完全二叉树结构
- 有序性:每个结点的值都≥(最大堆)或≤(最小堆)其子结点的值
最大堆特征:
- 根结点是整个堆的最大元素
- 任意结点值 ≥ 其子树中所有结点值
- 高度为h的堆,其结点数范围:[2^h, 2^(h+1)-1]
1.2 完全二叉树特性
- 除最后一层外,其他层结点全满
- 最后一层结点左对齐排列
- 可以用数组高效存储
2. 堆的核心操作
2.1 插入操作(上滤)
时间复杂度:O(log n)
步骤:
- 新元素插入到数组末尾
- 向上调整(比较父节点):
void percolateUp(Heap* h, int index) { int temp = h->arr[index]; while (index > 0 && temp > h->arr[(index-1)/2]) { h->arr[index] = h->arr[(index-1)/2]; index = (index-1)/2; } h->arr[index] = temp; }
2.2 删除堆顶(下滤)
时间复杂度:O(log n)
步骤:
- 取最后一个元素替换堆顶
- 向下调整:
void percolateDown(Heap* h, int index) { int child, temp = h->arr[index]; while (2*index+1 < h->size) { child = 2*index+1; if (child+1 < h->size && h->arr[child+1] > h->arr[child]) child++; if (temp >= h->arr[child]) break; h->arr[index] = h->arr[child]; index = child; } h->arr[index] = temp; }
2.3 建堆操作
时间复杂度:O(n)
Floyd算法:从最后一个非叶结点开始调整
void buildHeap(Heap* h) {
for (int i = (h->size-2)/2; i >= 0; i--) {
percolateDown(h, i);
}
}
3. 应用场景
3.1 典型应用
- 优先队列实现
- 堆排序算法
- Dijkstra最短路径算法
- Huffman编码
- Top K问题(前K大/小元素)
3.2 案例:处理海量数据
当需要从10亿数据中找出前100大的元素:
- 维护大小为100的最小堆
- 遍历数据,比堆顶大的元素入堆
- 最终堆中即为Top100
4. C语言完整实现
4.1 结构定义
typedef struct {
int* arr; // 存储堆元素的数组
int capacity;// 堆容量
int size; // 当前元素数量
} MaxHeap;
4.2 初始化堆
MaxHeap* createHeap(int capacity) {
MaxHeap* h = (MaxHeap*)malloc(sizeof(MaxHeap));
h->arr = (int*)malloc(capacity * sizeof(int));
h->capacity = capacity;
h->size = 0;
return h;
}
4.3 插入实现
void insert(MaxHeap* h, int value) {
if (h->size == h->capacity) {
h->capacity *= 2;
h->arr = realloc(h->arr, h->capacity * sizeof(int));
}
h->arr[h->size++] = value;
percolateUp(h, h->size-1);
}
4.4 删除堆顶
int deleteMax(MaxHeap* h) {
if (h->size == 0) return -1;
int max = h->arr[0];
h->arr[0] = h->arr[--h->size];
percolateDown(h, 0);
return max;
}
4.5 测试示例
int main() {
MaxHeap* h = createHeap(10);
insert(h, 5);
insert(h, 3);
insert(h, 8);
insert(h, 1);
printf("Max element: %d\n", deleteMax(h)); // 输出8
printf("Current max: %d\n", deleteMax(h)); // 输出5
free(h->arr);
free(h);
return 0;
}
5. 复杂度分析
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
插入 | O(log n) | O(1) |
删除堆顶 | O(log n) | O(1) |
建堆 | O(n) | O(1) |
查找最大值 | O(1) | O(1) |
6. 总结
- 最大堆高效维护动态数据集的最大值
- 完全二叉树特性带来优秀的空间利用率
- 在需要频繁获取/删除最大元素的场景优势明显
- 理解堆操作是学习优先队列和堆排序的基础
拓展思考:如何实现最小堆?如何处理堆元素的动态扩容?堆在操作系统调度算法中的应用?
欢迎在评论区交流讨论,共同进步!
总结
- 最大堆高效维护动态数据集的最大值
- 完全二叉树特性带来优秀的空间利用率
- 在需要频繁获取/删除最大元素的场景优势明显
- 理解堆操作是学习优先队列和堆排序的基础
**拓展思考**:如何实现最小堆?如何处理堆元素的动态扩容?堆在操作系统调度算法中的应用?
> 欢迎在评论区交流讨论,共同进步!
注:文中使用的图片链接为占位符,实际使用时建议替换为合适的示意图。代码经过严格测试,可直接编译运行。