数据结构之堆:原理与实现
创作时间:
作者:
@小白创作中心
数据结构之堆:原理与实现
引用
CSDN
1.
https://blog.csdn.net/CHENWENFEIc/article/details/144111705
堆(Heap)是一种特殊的数据结构,它基于完全二叉树并具有特定的排序性质。堆在计算机科学中有着广泛的应用,包括优先队列、堆排序等。本文将详细介绍堆的基本概念、存储结构、核心操作以及应用场景。
1. 什么是堆?
堆(Heap)是一种特殊的完全二叉树,它的每个节点都遵循以下性质之一:
- 最大堆(Max-Heap):每个节点的值都大于等于其子节点的值,根节点是最大值。
- 最小堆(Min-Heap):每个节点的值都小于等于其子节点的值,根节点是最小值。
堆的主要特点是便于快速获取最大值或最小值,因此堆广泛用于优先队列、堆排序等场景。
2. 堆的存储结构
堆通常用数组存储,其逻辑结构是树形,但存储方式是顺序存储(数组)。堆节点的索引关系如下:
- 父节点:索引为
i
的节点的父节点在索引(i-1)/2
。 - 左子节点:索引为
i
的节点的左子节点在索引2*i+1
。 - 右子节点:索引为
i
的节点的右子节点在索引2*i+2
。
堆的数组表示示例: 对于完全二叉树:
10
/ \
9 8
/ \ / \
7 6 5 4
对应的数组存储为:
[10, 9, 8, 7, 6, 5, 4]
。
3. 堆的操作
堆的核心操作包括:
- 插入(Insert):在堆中添加新元素,并维护堆的性质。
- 删除(Delete):从堆中移除根节点(最大堆中的最大值或最小堆中的最小值),并维护堆的性质。
- 堆化(Heapify):调整堆以恢复堆性质,分为向上调整和向下调整。
其中向下调整如图:
4. 堆的实现
以下是用C语言实现最大堆的代码示例:
- 堆的定义和初始化
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *data; // 数组存储堆的元素
int size; // 当前堆中元素数量
int capacity; // 堆的容量
} Heap;
// 初始化堆
Heap* createHeap(int capacity) {
Heap* heap = (Heap*)malloc(sizeof(Heap));
heap->data = (int*)malloc(sizeof(int) * capacity);
heap->size = 0;
heap->capacity = capacity;
return heap;
}
- 插入操作(Insert)
插入新元素时,需要将元素放到堆的最后,然后通过向上调整恢复堆的性质。
void insert(Heap* heap, int value) {
if (heap->size >= heap->capacity) {
printf("堆已满,无法插入元素。\n");
return;
}
heap->data[heap->size] = value; // 将新元素放在堆的末尾
int i = heap->size;
heap->size++;
// 向上调整
while (i > 0 && heap->data[i] > heap->data[(i-1)/2]) {
// 如果当前节点大于父节点,交换两者
int temp = heap->data[i];
heap->data[i] = heap->data[(i-1)/2];
heap->data[(i-1)/2] = temp;
i = (i-1)/2; // 更新当前节点为父节点
}
}
- 删除操作(Delete)
删除最大堆中的根节点(即最大值)时,需要将堆的最后一个元素放到根节点位置,并通过向下调整恢复堆的性质。
int deleteMax(Heap* heap) {
if (heap->size <= 0) {
printf("堆为空,无法删除元素。\n");
return -1;
}
int maxValue = heap->data[0]; // 根节点的值即为最大值
heap->data[0] = heap->data[heap->size - 1]; // 用最后一个元素替换根节点
heap->size--;
int i = 0;
while (2*i+1 < heap->size) { // 检查是否有左子节点
int maxChild = 2*i+1; // 假设左子节点为较大子节点
if (2*i+2 < heap->size && heap->data[2*i+2] > heap->data[2*i+1]) {
maxChild = 2*i+2; // 如果右子节点更大,则更新为右子节点
}
if (heap->data[i] >= heap->data[maxChild]) {
break; // 如果当前节点大于等于较大子节点,堆已调整完毕
}
// 交换当前节点和较大子节点
int temp = heap->data[i];
heap->data[i] = heap->data[maxChild];
heap->data[maxChild] = temp;
i = maxChild; // 更新当前节点为较大子节点
}
return maxValue;
}
- 打印堆内容
void printHeap(Heap* heap) {
for (int i = 0; i < heap->size; i++) {
printf("%d ", heap->data[i]);
}
printf("\n");
}
- 测试堆的操作
int main() {
Heap* heap = createHeap(10);
insert(heap, 15);
insert(heap, 10);
insert(heap, 30);
insert(heap, 25);
printf("当前堆: ");
printHeap(heap);
printf("删除最大值: %d\n", deleteMax(heap));
printf("当前堆: ");
printHeap(heap);
free(heap->data);
free(heap);
return 0;
}
5. 堆的应用场景
- 优先队列:基于堆实现的优先队列可以快速获取优先级最高的元素。
- 堆排序:堆是一种高效的排序工具,时间复杂度为O(n log n)。
- 图算法:在Dijkstra最短路径算法和Prim最小生成树算法中,堆用于高效选择最小权重边。
- Top K问题:用最小堆快速找到一组数据中的前K大元素。
6. 堆的优缺点
特性 | 优点 | 缺点 |
---|---|---|
存储方式 | 数组存储,结构紧凑 | 动态扩展时需要重新分配内存 |
操作效率 | 插入和删除的时间复杂度为O(log n) | 查找特定元素需要遍历整个堆,时间复杂度为O(n) |
实现复杂度 | 算法简单,易于实现 | 对于大数据场景,调整操作可能有一定性能开销 |
热门推荐
汉武帝独尊儒术:巩固中央集权与文化认同的历史转折
湖北赤壁:赤壁乡村六条徒步线路推荐,沿途皆是美景!
流脑和乙脑的相同点和不同点
英语:全肢体反应教学法(TPR)
同一个城市,同层级不同的公务员单位,待遇会有很大的差别吗?
肾病看什么科
软件系统成本估算全攻略:从人力到风险的全方位解析
股票如何建仓加仓?一文详解操作步骤与风险控制
黄心黑豆和绿心黑豆有什么区别?
比特币的风险与收益有哪些?一文搞清楚
管理模式创新的关键策略有哪些?
欧式别墅设计方案如何提升居住品质与空间利用效率?
美国本科艺术类专业就业前景如何
商标侵权的定义、判定方式及处罚标准
2030年AI颠覆行业需求,中国学生却「卷错方向」
自由空间光通信:未来通信技术的新趋势
网站建设完成后,在电子商务网站中,如何提高商品搜索曝光率
全球汇率市场动荡:日韩巴西相继出手稳定汇率
如何通过春夏秋冬八字命理分析详解个人命运
墙体一般多厚
羽绒服填充绒料不同对舒适度的影响
枳实和枳壳:同源不同效的中药解析
追讨欠款技巧:保持冷静理智,避免情绪主导行动
燃气卡丢失怎么办?补办流程及注意事项全解析
原创研究|基因工程与纳米药物,开辟阿尔茨海默病精准靶向和协同治疗新航道
vary from to和range from to的区别
心情不好怎么办?三步骤厘清心情不好的原因,7招迎接好心情!
如何理解中阳线的市场意义?这种阳线对投资决策有何指导?
为什么传统祁红是“碎”的?
华为平板刷机教程:从入门到精通的完整指南