C 语言数组方式实现最小堆
堆的定义:堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值
最小堆的二叉树元素和数组下标的对应关系
int arr[] = { 1, 2, 3, 4, 5, 6, 7 };
// 这对应的一棵最小堆二叉树如下
1
2 3
4 5 6 7
// 再一个更普通的最小堆例子如下
int arr2[] = { 3, 5, 7, 99, 12 };
3
5 7
99 12
由上可以很容易得到规律: 父节点 下标 n1 和子节点下标 n2 存在关系 n1 = n2 / 2
但是并不一定是按照从左到右,从上到下的递增关系,如上第二个例子
堆的插入和删除
// 在堆的末尾插入 元素2
3
5 7
99 12 2<<
// 父节点和子节点进行比较 2 < 7 交换 2 和 7
3
5 2<<
99 12 7
// 父节点和子节点进行比较 2 < 3 交换 2 和 3
2<<
5 3
99 12 7
// 再一次成为了一颗最小堆二叉树,每个子节点大于父节点
删除 节点2 示例
<<
5 3
99 12 7 11
// 左子结点和右子节点进行比较 5 < 3 将 3 提到上一层
3
5 <<
99 12 7 11
// 左子结点和右子节点进行比较 7 < 11 将 7 提到上一层
2
5 3
99 12 << 11
// 到达叶子节点 与堆的最后一个元素交换
2
5 3
99 12 11 <<
// 再一次成为了一颗最小堆二叉树,每个子节点大于父节点
实现代码
#include <stdio.h>
const long MaxSizeOfPile = 999;
const long MaxNum = 9999;
// The Min Pile
struct Pile {
int arr[MaxSizeOfPile];
int size;
};
void InitPile(struct Pile * pile) {
pile->size = 0;
}
void Insert(struct Pile * pile, int data) {
int pos = pile->size+1;
pile->arr[pos] = data;
while(pile->arr[pos] < pile->arr[pos/2] && pos > 1) {
int temp = pile->arr[pos];
pile->arr[pos] = pile->arr[pos/2];
pile->arr[pos/2] = temp;
pos /= 2;
}
++pile->size;
}
int Min(struct Pile * pile) {
return pile->arr[1];
}
int EraseMin(struct Pile * pile) {
int result = pile->arr[1];
if(pile->size%2 == 0) {
pile->arr[pile->size+1] = MaxNum;
}
int pos = 2, leaf = pos;
while(pos <= pile->size) {
if(pile->arr[pos] < pile->arr[pos+1]) {
pile->arr[pos/2] = pile->arr[pos];
leaf = pos;
} else {
pile->arr[pos/2] = pile->arr[pos+1];
leaf = ++pos;
}
pos *= 2;
}
if(pile->size > 0) {
pile->arr[leaf] = pile->arr[pile->size];
--pile->size;
}
return result;
}
int main(void)
{
struct Pile pile;
InitPile(&pile);
Insert(&pile, 3);
Insert(&pile, 10);
Insert(&pile, 9);
Insert(&pile, 11);
Insert(&pile, 12);
Insert(&pile, 5);
Insert(&pile, 2);
printf("min of pile %d\n", EraseMin(&pile));
for(int i=1; i<=pile.size; i++) {
printf("%d ", pile.arr[i]);
}
return 0;
}