堆
1. 什么是堆
引:
优先队列:特殊的“队列”,取出元素的顺序是依照元素的 优先权(关键字) 大小,而不是元素进入队列后的先后顺序。
若采用数组或链表实现优先队列
是否可以采用二叉树的存储结构?
- 不能用二叉搜索树:如果每次删除最大,最后会变为一颗斜树
- 堆!
堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点的值的完全二叉树被称之为堆。
堆的两个特性
- 结构性:用数组表示的完全二叉树
- 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)
- “最大堆”,也称“大顶堆”:每个父结点是其子结点的最大值
- “最小堆”,也称“小顶堆”:每个父结点是其子结点的最小值
2. 最大堆的操作
-
最大堆的插入
-
最大堆的删除
-
最大堆的建立
建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中
- 方法一:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间代价最大为O(NlogN)。
- 方法二:在线性时间复杂度下建立最大堆
- 将N个元素按输入顺序存入,先满足完全二叉树的结构特性
- 调整个结点位置,以满足最大堆的有序特性
具体操作:
#include <iostream>
using namespace std;
#define MAXDATA 10000
typedef int ElemType;
struct Heap {
ElemType* data;
int size; // 堆当前元素个数
int capacity; // 堆的最大容量
};
// !!!下面均是对最大堆的操作
// !!!data[0] 是哨兵!!!
// 建堆
Heap* createHeap(int maxSize)
{
Heap* H = new Heap;
H->data = new ElemType[maxSize];
H->size = 0;
H->capacity = maxSize;
H->data[0] = MAXDATA;
return H;
}
// 插入
bool insertHeap(Heap* H, ElemType key)
{
if (H->size == H->capacity) {
return false;
}
int i = ++H->size; // i 指向插入后堆中的最后一个元素位置
for (; H->data[i / 2] < key; i /= 2) {
H->data[i] = H->data[i / 2]; // 下沉结点
}
// 退出for循环说明已经找到给新插入结点的合适位置了
H->data[i] = key; // 插入key
}
// 删除最大元素
bool deleteMax(Heap* H, ElemType& maxKey)
{
if (H->size == 0) {
return false;
}
int parent, child;
ElemType temp;
maxKey = H->data[1]; // 取出根结点的最大值
// 用最大堆中最后一个元素从根结点开始向上过滤下层结点
temp = H->data[H->size--];
for (parent = 1; parent * 2 <= H->size; parent = child) {
child = parent * 2;
if ((child != H->size) && (H->data[child] < H->data[child + 1])) {
child++;
}
if (temp >= H->data[child]) break;
else {
H->data[parent] = H->data[child];
}
}
H->data[parent] = temp;
return true;
}