一、什么是堆?
在编程的世界里,我们常常需要处理这样一类问题:如何从一组数据中快速找到最大值或最小值?如何高效地管理具有不同优先级的任务?这些问题的答案之一,就是今天我们要深入探讨的数据结构——堆。
想象一下医院的急诊科。当病人来到急诊室时,护士不会简单地按照到达顺序安排就诊,而是会根据病情的紧急程度来决定谁先看医生。心脏病发作的病人会比感冒的病人优先得到治疗,这就是一种优先级管理。
堆在计算机世界中的作用,就类似于急诊科的这种优先级管理系统。它能够让我们快速找到最重要的元素,并根据需要高效地添加或移除元素。
二、堆的两个基本特征
2.1 完全二叉树结构
堆是一棵完全二叉树。一棵树,除了最后一层外,其他层都是"满"的,而最后一层的节点都尽量靠左排列。这种结构有个很好的特性:它可以用简单的数组来存储,而不需要复杂的指针连接。
在数组中(下标从 0 开始),对于任意位置 i 的元素:
- 它的父节点在位置
i/2(向下取整) - 左子节点在位置
2*i - 右子节点在位置
2*i+1
这种表示方式既节省内存,又访问高效。
如果从 1 开始取下标公式会简单一点,但实际编程我们都习惯数组从 0 开始。
2.2 有序性特征
**堆具有特定的顺序关系。**这分为两种情况:
- 最大堆:每个父节点的值都大于或等于其子节点的值。
- 最小堆:每个父节点的值都小于或等于其子节点的值。
注意:堆只保证父子之间的大小关系,不保证兄弟之间的顺序。
三、优先队列:堆的实际应用
在 C++ 中,我们通常不直接操作堆,而是通过一个叫做 priority_queue(优先队列)的容器来使用堆的功能。
3.1 优先队列的基本用法
让我们先看一个简单的例子。假设我们要管理一组数字,并总是能快速得到其中最大的数字:
#include <queue>
#include <iostream>
using namespace std;
int main() {
// 创建一个最大堆(默认)
priority_queue<int> maxHeap;
// 添加一些数字
maxHeap.push(30);
maxHeap.push(10);
maxHeap.push(50);
maxHeap.();
cout << << maxHeap.() << endl;
maxHeap.();
cout << << maxHeap.() << endl;
;
}


