一、概念
一个关键码的集合,把这个集合的所有元素按完全二叉树顺序存储方式存储在一个一维数组中,并且满足任何一个元素的左右孩子的值均小于这个元素的值。这是小堆,大堆反之。说了这么多,不如两张图来说明一下!!!
下面我们看一下堆的基本操作。
备注:小堆实现对基本操作。
Heap.h
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int HPDataType;
typedef int (*compare)(HPDataType left,HPDataType right);
typedef struct Heap
{
int capacity;
int size;
HPDataType *array;
compare cmp;
}Heap;
void HeapInit(Heap *hp,compare com);
//初始化
void Greater(HPDataType left,HPDataType right);
//大堆
void Less(HPDataType left,HPDataType right);
//小堆
void Swap(HPDataType *left,HPDataType *right);
//交换
void AdjustDown(Heap *hp,int parent);
//向下调整
void CreateHeap(Heap *hp,int *array,int size,compare com);
//创建堆
void CheckCapacity(Heap *hp);
//检查容量
void AdjustUp(Heap *hp, int child);
//向上调整
void HeapInsert(Heap *hp,HPDataType data);
//插入
void HeapRemove(Heap *hp);
//删除
void HeapDestroy(Heap *hp);
//销毁
HPDataType HeapTop(Heap *hp);
//取堆顶
int HeapSize(Heap *hp);
//堆的大小
int HeapEmpty(Heap *hp);
//判空
Heap.c
void HeapInit(Heap *hp,compare cmp)
{
assert(hp);
hp->array = (HPDataType*)malloc(sizeof(HPDataType)*3);
if(NULL == array)
{
assert(0);
return;
}
hp->cmp = cmp;
hp->capacity = 3;
hp->size = 3;
}
void Greater(HPDataType left,HPDataType right)
{
return left>right;
}
void Less(HPDataType left,HPDataType right)
{
return left<right;
}
void Swap(HPDataType *left,HPDataType *right)
{
HPDataType tmp = 0;
tmp = *left;
*left = *right;
*right = tmp;
}
void AdjustDown(Heap *hp,int parent)
{
assert(hp);
int child = (parent<<1)+1;
//默认左孩子小于有孩子
while(child<hp->size)
{
//如果有孩子比左孩子小,则换掉较小值的索引
if(child+1<hp->size && hp->cmp(hp->array[child+1],hp->array[child]))
child = child+1;
if(hp->cmp(hp->array[child],hp->array[parent]))
{
Swap(&hp->array[child],&hp->array[parent]);
parent = child;
child = (parent<<1)+1;
}
else
{
return;
}
}
}
void HeapCreate(Heap *hp,int *array,int size,compare cmp)
{
int root = ((size-1)-1)>>1;//找到第一个非叶子节点
int i = 0;
assert(hp);
hp->array = (HPDataType*)malloc(sizeof(HPDataType));
if(NULL == hp->array)
{
assert(0);
return;
}
hp->capacity = size;
hp->size = size;
memcopy(hp->array,array,size*sizeof((HPDataType)));
for(i=root;i>=0;i--)
AdjustDown(Heap *hp,int parent);
}
void CheckCapacity(Heap *hp)
{
assert(hp);
if(hp->capacity == hp->size)
{
hp->array = (HPDataType*)realloc(hp->array,sizeof(HPDataType)*(hp->capacity)*2);//扩容为原来的二倍
if(NULL == hp->array)
{
assert(0);
return;
}
hp->capacity = 2*(hp->capacity);
}
}
void AdjustUp(Heap *hp,int child)
{
assert(hp);
int parent = (child-1)>>1;
while(parent)
{
if(hp->cmp(hp->array[child],hp->array[parent]))
//因为插入操作之前本身满足堆的性质,所以只需要比较插入节点的值与其父节点的值
{
Swap(hp->array[child],hp->array[parent]);
child = parent;
parent = (child-1)>>1;
}
else
{
return;
}
}
}
void HeapInsert(Heap *hp,HPDataType data)
{
assert(hp);
CheckHeap(hp);
hp->array[hp->size++] = data;
AdjustUp(hp,hp->size-1);
}
void HeapRemove(Heap *hp)
{
assert(hp);
if(HeapEmpty(hp))
return;
Swap(&hp->array[hp->size-1],hp->array[0]);
hp->size--;
AdjustDown(hp,0);
}
void Destroy(Heap *hp)
{
assert(hp);
free(hp);
hp->array = 0;
hp->capacity = 0;
hp->size = 0;
}
HPDataType HeapTop(Heap *hp)
{
assert(hp);
return hp->array[0];
}
int HeapSize(Heap *hp)
{
assert(hp);
return hp->size;
}
int HeapEmpty(Heap *hp)
{
assert(hp);
return 0 == hp->size;
}
test.c
int main()
{
Heap hp;
int array[] = { 7, 3, 4, 6, 2, 9 };
CreateHeap(&hp, array, sizeof(array) / sizeof(array[0]), Less);
HeapInsert(&hp, 1);
HeapRemove(&hp);
getchar();
return 0;
}