堆的基本概念:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: Ki <= K2*i+1 且 Ki<= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2) i =0,1,2…,则称为小堆(或大堆)
如下图:分别为小堆和大堆
堆的操作具体代码如下:
测试环境:vs2013
Heap.h
#ifndef __HEAP_H__
#define __HEAP_H__
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int DataType;
typedef int(*Compare)(DataType left, DataType right);//比较方法的函数指针
//堆的内容
typedef struct Heap
{
DataType* arr;//连续的存储空间
int _Capacity;//空间总容量
int _size;//有效元素个数
Compare com;
}Heap;
//初始化堆
void HeapInit(Heap* hp, Compare com);
//比较方法
//大堆
int Greater(DataType left, DataType right);
//小堆
int Less(DataType left, DataType right);
//堆的创建
void CreateHeap(Heap* hp, DataType* arr, int size);
//插入元素
void InsertHeap(Heap* hp, DataType data);
//删除堆顶元素
void DeleteHeap(Heap* hp);
//查看堆顶元素
DataType HeapTop(Heap* hp);
//查看堆总元素个数
int HeapSize(Heap* hp);
//堆判空
int EmptyHeap(Heap* hp);
//销毁堆
void DestoryHeap(Heap* hp);
#endif
Heap.c
#include "Heap.h"
//初始化堆
void HeapInit(Heap* hp, Compare com)
{
assert(hp);
hp->arr = (DataType*)malloc(sizeof(DataType)*3);
if (NULL == hp->arr)
{
assert(0);
return;
}
//申请成功
hp->_Capacity = 3;
hp->_size = 3;
hp->com = com;
}
//比较方法
//大堆
int Greater(DataType left, DataType right)
{
if (left > right)
return 1;
return 0;
}
//小堆
int Less(DataType left, DataType right)
{
if (left < right)
return 1;
return 0;
}
void _Swap(DataType* left, DataType* right)
{
DataType 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->com(hp->arr[child + 1], hp->arr[child]))
child += 1;
//如果双亲比孩子大,交换
if (hp->com(hp->arr[child], hp->arr[parent]))
{
_Swap(&(hp->arr[child]), &(hp->arr[parent]));
//向下走,因为调整之后可能会破坏下面的堆、
parent = child;
child = (parent << 1) + 1;
}
//说明已经是堆
else
return;
}
}
//堆的创建
void CreateHeap(Heap* hp, DataType* arr, int size)
{
int i = 0;
int root = (size - 2) / 2;//标记第一个非叶子节点
assert(hp);
//先给堆申请空间
hp->arr = (DataType*)malloc(sizeof(DataType)*size);
if (NULL == arr)
{
assert(0);
return;
}
//申请成功
hp->_Capacity = size;
hp->_size = size;
//将数组元素放入堆中
for (; i < size; i++)
hp->arr[i] = arr[i];
//用向下调整法调整堆
for (i = root; i >= 0; i--)
_AdjustDown(hp, i);
}
void _CheckCapacity(Heap* hp)
{
assert(hp);
if (hp->_Capacity == hp->_size)//说明空间已满
{
hp->arr = (DataType*)realloc(hp->arr, sizeof(DataType)*(hp->_Capacity) * 2);//扩容位原空间2倍
if (NULL == hp->arr)
{
assert(0);
return;
}
hp->_Capacity = 2 * hp->_Capacity;
}
}
//向上调整法
void _AdjustUp(Heap* hp, int child)
{
int parent = (child - 1) >> 1;
assert(hp);
while (child != 0)
{
//如果孩子小于双亲,交换
if (hp->com(hp->arr[child], hp->arr[parent]))
{
_Swap(&(hp->arr[child]), &(hp->arr[parent]));
//朝上走,因为交换完可能破坏上面的堆
child = parent;
parent = (child - 1) >> 1;
}
//说明已经是堆
else
return;
}
}
//插入元素
void InsertHeap(Heap* hp, DataType data)
{
assert(hp);
//检查空间
_CheckCapacity(hp);
//在堆尾插入元素
hp->arr[hp->_size++] = data;
//用向上调整法调整堆
_AdjustUp(hp, hp->_size - 1);
}
//删除堆顶元素
void DeleteHeap(Heap* hp)
{
assert(hp);
//判断堆是否为空
if (EmptyHeap(hp))
return;
//先将堆顶元素和堆尾元素交换,并删除堆尾元素
_Swap(&(hp->arr[0]), &hp->arr[hp->_size - 1]);
hp->_size--;
//用向下调整法调整队列
_AdjustDown(hp, 0);
}
//查看堆顶元素
DataType HeapTop(Heap* hp)
{
assert(hp);
if (hp->_size == 0)
{
assert(0);
return 0;
}
return hp->arr[0];
}
//查看堆总元素个数
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size;
}
//堆判空
int EmptyHeap(Heap* hp)
{
assert(hp);
if (hp->_size == 0)
return 1;
return 0;
}
//销毁堆
void DestoryHeap(Heap* hp)
{
assert(hp);
hp->_size = 0;
hp->_Capacity = 0;
free(hp->arr);
hp->arr = NULL;
return;
}
test.c
#include "Heap.h"
void Test1()
{
int i = 0;
Heap hp;
DataType arr[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
int size = sizeof(arr) / sizeof(arr[0]);
HeapInit(&hp, Less);//初始化堆
CreateHeap(&hp, arr, size);//创建堆,最后一个参数是函数指针类型,选择创建大堆或小堆
InsertHeap(&hp, 11);//向堆插入元素
DeleteHeap(&hp);//删除堆顶元素
printf("Top = %d Size = %d\n", HeapTop(&hp), HeapSize(&hp));
DestoryHeap(&hp);//销毁堆
}
int main()
{
Test1();//测试堆
}