堆的数据结构
对于堆, 有最大堆和最小堆, 在定义一个堆的时候用一个数组表示堆, 同时为了方便定义堆的大小, 用一个 size 表示堆的有效元素, 同时为了区别最大堆和最小堆, 我们用一个函数指针表示这个堆是最大堆还是最小堆.
typedef int (*Compare)(HeapType parent, HeapType child);
typedef struct Heap {
HeapType data[HeapMaxSize];
int size;
Compare cmp;
} Heap;
堆的初始化
int Greater(HeapType parent, HeapType child)
{
return parent > child? 1 : 0;
}
int Less(HeapType parent, HeapType child)
{
return parent < child ? 1 : 0;
}
void HeapInit(Heap* heap, Compare cmp)
{
if(heap == NULL)
{
return;
}
heap -> size = 0;
heap -> cmp = cmp;
}
堆的插入
先将要插入得到元素插入到堆对应的数组的最后一个位置, 然后判断插入结点的值和它的父节点是否符合堆的特征(最大堆:根节点大于它的左孩子和有孩子, 最小堆根节点小于它的左孩子和有孩子), 此时如果插入结点和它的父节点符合堆的特性就直接退出, 如果根节点和父节点不符合堆的特性, 此时就需要将插入结点和它的根节点进行交换, 直到符合堆的特性为止
void HeapInsert(Heap* heap, HeapType value)
{
if(heap == NULL)
{
return;//非法输入
}
if(heap -> size >= HeapMaxSize)
{
return;
}
//先将 value 插入到末尾
heap -> data[heap -> size++] = value;
//判断父节点和 value 是否符合规定
int child = heap -> size - 1;
int parent = (child - 1) / 2;
while(child > 0)
{
//如果不符合, 就直接将插入的结点和它的父节点进行交换
if(heap -> cmp(heap -> data[parent], heap -> data[child]) == 0)
{
Swap(&heap -> data[parent], &heap -> data[child]);
child = parent;
parent = (child -1) / 2;
}
//如果符合, 就退出
else
{
break;
}
}
}
取堆顶元素
直接返回堆对用的数组的第一个元素
int HeapRoot(Heap* heap, HeapType* value)
{
if(heap == NULL || value == NULL)
{
return 0;
}
*value = heap -> data[0];
return 1;
}
删除堆
先将堆的最后一个元素和堆的第一个结点进行交换, 将堆的大小减1, 此时由于交换了两个元素, 因此可能会破坏堆的结构.先判断父节点是否有右孩子, 如果有右孩子, 就将左右孩子中比较满足多结构的一个标记下来, 接着判断父节点和左右孩子较满足堆结构的的结点是否需要交换, 如果需要交换就将两个交换, 否则就直接退出
void HeapErase(Heap* heap)
{
if(heap == NULL)
{
return;
}
if(heap -> size == 0)
{
return;
}
//将对顶元素和最后一个元素进行交换
Swap(&heap -> data[0], &heap -> data[heap -> size - 1]);
--heap -> size;
int parent = 0;
int child = 2 * parent + 1;
while(parent >= 0 && parent < heap -> size && child >= 0 && child < heap -> size)
{
//判断是否有右子树
if(child + 1 < heap -> size)
{
//判断出左右孩子中较满足对特性的一个元素
if(heap -> cmp(heap -> data[child], heap -> data[child + 1]) == 0)
{
child = child + 1;
}
//判断是否需要下沉
if(heap -> cmp(heap -> data[parent], heap -> data[child]) == 0)
{
Swap(&heap -> data[parent], &heap -> data[child]);
parent = child;
child = 2 * parent + 1;
}
else if(heap -> cmp(heap -> data[parent], heap -> data[child]) == 1)
{
return;
}
}
else
{
return;
}
}
}
堆的判空
判断堆所对应的的数组元素的个数是否为空, 如果为空就返回1, 否则就返回0
int HeapEmpty(Heap* heap)
{
if(heap == NULL)
{
return 1;
}
if(heap -> size == 0)
{
return 1;
}
return 0;
}
判断堆的元素的个数
int HeapSize(Heap* heap)
{
if(heap == NULL)
{
return 0;
}
return heap -> size;
}
堆的销毁
void HeapDestroy(Heap* heap)
{
if(heap == NULL)
{
return;
}
heap -> size = 0;
heap -> cmp = NULL;
}
堆排序
给定一个数组, 将这个数组按照对应的规则进行排序. 即先定义一个堆, 再将数组中的所有元素插入到堆中, 将堆中的元素删除, 最后恢复对的有效元素, 将堆中的内容全部拷贝到数组中
void HeapSort(HeapType array[], int size, Compare cmp)
{
if(array == NULL || size == 0)
{
return;
}
Heap heap;
HeapInit(&heap, cmp);
//先将数组中的元素插入到堆中
int i = 0;
for(; i < size; i++)
{
HeapInsert(&heap, array[i]);
}
//删除对中的所有元素
for(i = 0; i < size; i++)
{
HeapErase(&heap);
}
heap.size = size;
for(i = 0; i < size; i++)
{
array[i] = heap.data[i];
}
}