结构体
typedef int Type;//自定义类型
typedef struct HNode//堆结构体
{
Type *data;//存放堆的数组
int NowSize;//目前堆的大小
int MaxSize; //最大容量
} HNode;
创建空堆
HNode *CreatHeap()//创建一个空堆
{
HNode *H = (HNode*)malloc(sizeof(HNode));
H->data = (Type*)malloc(sizeof(Type)*(MAXSIZE+1));//因为从下标1开始存所以多申请一个空间
H->NowSize = 0;
H->MaxSize = MAXSIZE;
H->data[0] = MAXDATA;//设置哨兵(其实也可以不用...)
return H;
}
判空判满
int IsFull(HNode *H)//判满
{
return H->NowSize==H->MaxSize;
}
int IsEmpty(HNode *H)//判空
{
return H->NowSize == 0;
}
为堆中插入数值
void Swap(HNode *H,int a,int b)//交换H中两个值
{
Type temp = H->data[a];
H->data[a] = H->data[b];
H->data[b] = temp;
}
int Insert(HNode *H,Type val)//插入值val
{
if(IsFull(H))//判断是不是满了
return ERROR;
H->data[++H->NowSize] = val;//先放到最后一个位置
int i = H->NowSize;
int flag = 0;
while(flag == 0)//往上调整
{
if(H->data[i]>H->data[i/2])//如果双亲比自己小就是不满足最大堆,那就交换双亲和自己的数值
Swap(H,i,i/2);
else//否则说明已经满足最大堆了
flag = 1;
i /= 2;//往上走
}
return OK;
}
向下调整满足最大堆
//num 为调整的开始下标, size为需要调整的堆的大小
void SiftDown(HNode *H,int num,int size)//向下调整(最大堆)
{
int t,flag = 0;
while(num * 2 <= size && flag == 0)//先判断有没有左孩子
{
t = H->data[num] >= H->data[num*2] ? num : num*2;//记录下num和它的左孩子数值 较大的那个的下标
if(num*2+1 <= size)//如果有右孩子且右孩子更大,就记录右孩子的下标
t = H->data[t] >= H->data[num*2+1] ? t : num*2+1;
if(t == num)//如果发现自己比左右孩子都大说明已经满足最大堆了就让flag为1停止调整
flag = 1;
else//如果发现孩子比自己大就把最大的孩子和自己交换位置,然后继续往下
{
Swap(H,num,t);
num = t;
}
}
}
删除并返回堆中最大值
int DelMax(HNode *H,Type *Maxval)//删除并用 Maxval 返回最大值
{
if(IsEmpty(H))//看看是不是空的
return ERROR;
*Maxval = H->data[1];//因为满足最大堆所以堆顶的值最大,那就保存下来
H->data[1] = H->data[H->NowSize--];//把最后一个数补到第一个位置--记得大小减少一个
SiftDown(H,1,H->NowSize);//重新调整下让整体满足最大堆
return OK;
}
堆排
前提是最大堆…
通过调用前面的向下调整函数,使每次删除掉最大值仍满足最大堆
//将无序的堆调整为最大堆
void MaxHeap(HNode *H)//从最后一个叶子节点的双亲开始(因为叶子节点不用往下调整)往前逐个调整为最大堆
{
for(int i = H->NowSize/2; i>0; i--)
SiftDown(H,i,H->NowSize);
}
//堆排--前提是满足最大堆
void Heapsort(HNode *H)
{
for(int i = H->NowSize; i>1;)
{
Swap(H,1,i);//把目前最大的和目前最后一个数交换下位置,相当于把最大的数保存在最后一个位置
i--;//把最后一个位置"保护"起来
SiftDown(H,1,i);//调整使其满足最大堆
}
}
完整代码
//堆:使用完全二叉树来存放数据,这时候适合用数组来构建,会很有规律
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100 //最大数量
#define MAXDATA 2147483646 //哨兵--最大堆就取一个所存储数据无法达到的最大值,这样就不用规定i>0,效率更高...
#define ERROR 0
#define OK 1
typedef int Type;//自定义类型
typedef struct HNode//堆结构体
{
Type *data;//堆数组
int NowSize;//现在容量
int MaxSize; //最大容量
} HNode;
HNode *CreatHeap()//创建一个空堆
{
HNode *H = (HNode*)malloc(sizeof(HNode));
H->data = (Type*)malloc(sizeof(Type)*(MAXSIZE+1));//因为从下标1开始存所以多申请一个空间
H->NowSize = 0;
H->MaxSize = MAXSIZE;
H->data[0] = MAXDATA;//设置哨兵
return H;
}
int IsFull(HNode *H)//判满
{
return H->NowSize==H->MaxSize;
}
int IsEmpty(HNode *H)//判空
{
return H->NowSize == 0;
}
void Swap(HNode *H,int a,int b)//交换H中两个值
{
Type temp = H->data[a];
H->data[a] = H->data[b];
H->data[b] = temp;
}
//num 为调整的开始下标, size为需要调整的堆的大小
void SiftDown(HNode *H,int num,int size)//向下调整(最大堆)
{
int t,flag = 0;
while(num * 2 <= size && flag == 0)//先判断有没有左孩子
{
t = H->data[num] >= H->data[num*2] ? num : num*2;//记录下num和它的左孩子数值 较大的那个的下标
if(num*2+1 <= size)//如果有右孩子且右孩子更大,就记录右孩子的下标
t = H->data[t] >= H->data[num*2+1] ? t : num*2+1;
if(t == num)//如果发现自己比左右孩子都大说明已经满足最大堆了就让flag为1停止调整
flag = 1;
else//如果发现孩子比自己大就把最大的孩子和自己交换位置,然后继续往下
{
Swap(H,num,t);
num = t;
}
}
}
int Insert(HNode *H,Type val)//插入值val
{
if(IsFull(H))//判断是不是满了
return ERROR;
H->data[++H->NowSize] = val;//先放到最后一个位置
int i = H->NowSize;
int flag = 0;
while(flag == 0)//往上调整
{
if(H->data[i]>H->data[i/2])//如果双亲比自己小就是不满足最大堆,那就交换双亲和自己的数值
Swap(H,i,i/2);
else//否则说明已经满足最大堆了
flag = 1;
i /= 2;//往上走
}
return OK;
}
int DelMax(HNode *H,Type *Maxval)//删除并用 Maxval 返回最大值
{
if(IsEmpty(H))
return ERROR;
*Maxval = H->data[1];//因为满足最大堆所以堆顶的值最大,那就保存下来
H->data[1] = H->data[H->NowSize--];//把最后一个数补到第一个位置--记得大小减少一个
SiftDown(H,1,H->NowSize);//重新调整下让整体满足最大堆
return OK;
}
void MaxHeap(HNode *H)//从最后一个叶子节点的双亲开始(因为叶子节点不用往下调整)往前逐个调整为最大堆
{
for(int i = H->NowSize/2; i>0; i--)
SiftDown(H,i,H->NowSize);
}
void Heapsort(HNode *H)//堆排--前提是满足最大堆
{
for(int i = H->NowSize; i>1;)
{
Swap(H,1,i);//把目前最大的和目前最后一个数交换下位置,相当于把最大的数保存在最后一个位置
i--;//把最后一个位置"保护"起来
SiftDown(H,1,i);//调整使其满足最大堆
}
}
void Print(HNode *H)//展示
{
for(int i = 1; i<=H->NowSize; i++)
printf("%d ",H->data[i]);
}
void Free(HNode *H)//free
{
free(H->data);
free(H);
}
int main()
{
HNode *H = CreatHeap();
Type val;
printf("输入需要插入的数字以q结束:");
while(scanf("%d",&val)==1)
{
if(!Insert(H,val))
{
printf("NO Place");
break;
}
}
printf("\n存储的数字为:");
Print(H);
if(DelMax(H,&val))
{
printf("\n弹出最大的数字为:%d",val);
}
else
printf("Empty\n");
Heapsort(H);
printf("\n从小到大排序为:");
Print(H);
Free(H);
return 0;
}
效果图
参考《啊哈算法》《大话数据结构》
如果有错误请您指出,我一定洗耳恭听