二叉堆分为大顶堆和小顶堆,是一颗完全二叉树。但是实际上的存储一般用数组存储。
大顶堆:任何父节点都比子节点大,但左右子节点大小情况任意。
小顶堆:任何父节点都比子节点小,但左右子节点大小情况任意。
typedef int Type; // 键值类型
// 大顶堆
class MaxHeap {
public:
bool Insert(Type key); // 插入
bool Delete(Type key); // 删除
MaxHeap(int C = 10) :capaity(C), size(0), heap(new Type[capaity]) {}
private:
Type* heap; // 堆实际存储结构
int capaity; // 堆的容量大小
int size; // 堆存入键值数
};
若一个节点在数组下标为 i,则
父节点下标为(i-1)/2;
左孩子下标(2*i)+1;
右孩子下标(2*i)+2
以大顶堆举例,大顶堆与小顶堆的区别仅在于下调和上调时的判断条件不同。
插入:
// 插入
bool MaxHeap::Insert(Type key) {
if (size == capacity) return false; // 已满
heap[size] = key; // 插入尾部
// 将新插入的键值上移
int index = size; // 起始位置
int P = (index - 1) / 2;
while (index > 0) {
if (heap[P] >= key) break; // 若heap[P] <= key 则为小顶堆的判断条件
heap[index] = heap[P];
index = P;
P = (index - 1) / 2;
}
heap[index] = key;
++size;
return true;
}
删除:
// 删除
bool MaxHeap::Delete(Type key){
if (0 == size) return false;
int index = 0;
// 寻找到待删键值的位置
for (; index < size; ++index) {
if (heap[index] == key) break;
}
if (index == size)return false; // 不存在待删键值
// 尾部键值替换待删键值
heap[index] = heap[size - 1];
int C = 2 * index + 1;
while (C <= size) {
if (C < size&&heap[C] < heap[C + 1]) C = C + 1; // 选择左、右孩子当中较大的那个去替换
if (heap[index] >= heap[C]) break; // 不需要继续下移
// 若heao[index] <= heap[C] 则为小顶堆的判断条件
heap[index] = heap[C];
index = C;
C = 2 * index + 1;
}
--size;
return true;
}