1、用途:快速找到最大或最小元素,每一层的父节点始终大于或小于左右节点,左右节点之间没有关系。最底层最右端的节点就是最后一个节点。
2、节点成S行自上而下,自左向右顺序编号。元素对应在数组当中。若父节点编号为n,那么左右节点分别为2n+1,2n+2。可以随机访问,虽然属于二叉树,但是不用指针把每个节点串起来体现节点之间的关系。
有些定义放在xxxx.c中说明他们不是公共接口,可以访问的公共接口放在xxxx.h文件中。
3、数据结构
typedef struct _HEAP_H{
int size;
void **tree;
void (*destroy)(void *data);
int (*compare)(void *key1, void *key2);
}Heap;
4、初始化堆,释放堆
void heap_init(Heap *tree, void (*destroy)(void *data), int (*compare)(void *key1, void *key2))
{
tree->size = 0;
tree->tree = NULL;
tree->destroy = destroy;
tree->compare = compare;
return;
}
void heap_destroy(Heap *tree)
{
int i;
if(tree->destroy != NULL)
{
for(i = 0; i < heap_size(tree); i++)
{
tree->destroy(tree->tree[i]);
}
}
free(tree->tree);
memset(tree, 0, sizeof(Heap));
return;
}
5、向堆中插入元素
int heap_insert(Heap *heap, const void *data)
{
void *temp;
int ipos, ppos;
//动态扩展数组
if(( temp = (void **)realloc(heap->tree, (heap->size * sizeof(void *) + 1)) ) == NULL)
return -1;
else
{
heap->tree = temp;
}
//先把要插入的树存入尾部
heap->tree[heap_size(heap)] = (void *)data;
ipos = heap_size(heap);
ppos = heap_parent(ipos);
//父节点小,则一直和父节点进行交换
while(ipos > 0 && heap->compare(heap->tree[ppos], heap->tree[ipos]) < 0)
{
temp = heap->tree[ppos];
heap->tree[ppos] = heap->tree[ipos];
heap->tree[ipos] = temp;
ipos = ppos;
ppos = heap_parent(ipos);
}
heap->size++;
return 0;
}
6、删掉头部,即最大或最小的那个
//去掉头节点,重新排列
int heap_extract(Heap *heap, void **data)
{
void *save, *temp;
int ipos, lpos, rpos, mpos;
if(heap_size(heap) == 0)
return -1;
*data = heap->tree[0];
//先把最后一个元素保存起来,在缩小空间
save = heap->tree[heap_size(heap) - 1];
if(heap_size(heap) - 1 > 0)
{
if((temp = (void **)realloc(heap->tree, (heap_size(heap) - 1) * sizeof(void *))) == NULL)
return -1;
else
{
heap->tree = temp;
}
heap->size--;
}
//如果size == 1,重新初始化
else
{
free(heap->tree);
heap->tree = NULL;
heap->size = 0;
return 0;
}
heap->tree[0] = save; //最后一个元素移到顶部
ipos = 0;
while(1)
{
lpos = heap_left(ipos);
rpos = heap_right(ipos);
//左节点标号不能超过最大标号,且左节点大于父节点 ,用mpos保存大的那方
if((lpos < heap_size(heap)) && (heap->compare(heap->tree[lpos], heap->tree[ipos]) > 0))
{
mpos = lpos;
}
else
{
mpos = ipos;
}
if((rpos < heap_size(heap)) && heap->compare(heap->tree[rpos], heap->tree[ipos]) > 0)
{
mpos = rpos;
}
if(mpos == ipos)
{
break;//当前节点大于左右,结束循环
}
else
{
temp = heap->tree[mpos];
heap->tree[mpos] = heap->tree[ipos];
heap->tree[ipos] = temp;
ipos = mpos;//这里是标号,向下调整直到调整后的子树父节点大于左右
}
}
}