堆的概念
如果有一个关键码的集合K={k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:K[i] <= K[2i+1] 且 Ki<= K[2i+2] (K[i] >= K[2i+1] 且 K[i] >= K[2i+2]) i =
0,1,2…,则称为小堆(或大堆)。
- 堆的特点
小(大)堆中任一结点的关键码均小于(大于)等于它的左右孩子的关键码,位于堆顶结点的关键码最小(最大),从根节点到每个结点的路径上数组元素组成的序列都是递增(递减)的
堆的创建
思路
从最后一个非叶子结点开始调整,一直到根节点为止,将每个结点及其子
树调整到满足堆的性质即可
typedef struct Heap
{
int array[100];
int size;
} Heap;
// 初始化堆
void HeapInit(Heap* pH, int source[], int size)
{
for (int i = 0; i < size; i++)
{
pH->array[i] = source[i];
}
pH->size = size;
}
// 向下调整
void HeapAdjustDown(Heap* pH, int root)
{
int parent = root;
while (1)
{
int left = 2 * parent + 1;
if (left >= pH->size)
{
return;
}
int maxChild = left;
if (2 * parent + 2 < pH->size && pH->array[2 * parent + 2] > pH->array[left])
{
maxChild = 2 * parent + 2;
}
if (pH->array[parent] > pH->array[maxChild])
{
return;
}
// 交换 root 和 maxChild 下标所在的值
int t = pH->array[parent];
pH->array[parent] = pH->array[maxChild];
pH->array[maxChild] = t;
parent = maxChild;
}
}
// 建大堆
void MakeHeap(Heap* pH)
{
for (int i = (pH->size - 2) / 2; i >= 0; i--)
{
HeapAdjustDown(pH, i);
}
}
堆的插入和删除
- 删除(每次删除堆顶元素)
思路
- 将堆中最后一个元素代替堆顶元素
- 将堆中元素个数减少一个(相当于删除最后一个元素)
- 向下调整使其满足对的性质
void HeapPop(Heap *pH)
{
pH->array[0] = pH->array[pH->size - 1];
pH->size--;
HeapAdjustDown(pH, 0);
}
- 插入
思路
在已经建成的堆的后面插入新元素,插入之后,当树中结点不满足堆的性质时,就需要对堆进行重新调整(向上调整)
// 向上调整
void HeapAdjustUp(Heap *pH, int child)
{
int parent;
while (child > 0) {
parent = (child - 1) / 2;
if (pH->array[parent] >= pH->array[child]) {
return;
}
Swap(pH->array + parent, pH->array + child);
child = parent;
}
}
// 插入元素
void HeapPush(Heap *pH, int data)
{
assert(pH->size < 100);
pH->array[pH->size++] = data;
HeapAdjustUp(pH, pH->size - 1);
}
本文原码已上传至github:https://github.com/Sveter/C/tree/master/Heap