最大堆特性:首先要满足完全二叉树的结构;然后父结点都比子结点要大,兄弟结点没有顺序性;根节点为最大。
最大堆的结构:
typedef struct heap{
int *Date; //因为其完全二叉树的结构特性,用数组即可实现
int Size; //当前元素个数
int Capacity;//最大容量
}Maxheap;
堆的创建(空堆的创建)、堆的插入、堆的删除、判断是否为空、判断是否已满
Maxheap *creat(int MAXsize)
{
Maxheap *t;
t=(Maxheap*)malloc(sizeof(Maxheap));
t->Capacity=MAXsize; //容量
t->date=(int*)malloc(sizeof(int)*(MAXsize+1)); //加1是因为我们从数组的第1开始操作而不是第0
t->Size=0;
t->Date[0]=MAX; //将第0个定为某个很大的数字 对堆的操作是从第1个开始的
return t;
}
//判断是否为空/满
```csharp
int isfull(Maxheap *t)
{
if(t->Size==t->Capacity)
return 1;
else
return 0;
}
int isempty(Maxheap *t)
{
if(t->Size==0)
return 1;
else
return 0;
}
对最大堆的插入,首先定位到最后一个结点处的后一位 即i=++size
然后判断该点的父结点(i/2)是否比它大,如果比它大那么直接放在i的位置,否则就需要换位置了
void Insert(Maxheap *t,int x)
{
if(isfull(t))
{
printf("堆已满,无法插入\n");
return;
}
int i;
i=++t->Size; //让i指向当前元素个数的后一位 同时size+1
for(;t->Date[i/2]<x;i/=2) //顺着父亲结点往上寻找 看看还有没有比他小的 让大的当爹
t->Date[i]=t->Date[i/2]; //把父节点往下移动
t->Date[i]=x; //将x归位
}
对堆的删除,其实就是删除根结点(最大值),然后把他的儿子结点按最大堆的特性放好。
删掉了根结点,我们需要找到它最大的儿子,让它最大的儿子放在它的位置。
int Delet(Maxheap *t)
{
if(isempty(t))
{
printf("堆是空的,无法删除\n");
return;
}
int dad,child,MAXTEMP,temp;
temp=t->Date[t->Size--]; //保存下最后的那个儿子 顺便让size减一
MAXTEMP=t->Date[1];//把根节点取出来
for(dad=1;dad*2<=t->Size;dad=child)
{
child=dad*2; //左儿子
if(child+1<=t->Size&&t->Date[child]<t->Date[child+1]) //右儿子
child+=1; //找出比较大的儿子
if(temp>t->Date[child]) //如果temp比谁都大
break;
else
t->Date[dad]=t->Date[child]; //把父亲结点删除 大儿子上位
}
t->Date[dad]=temp; //把temp归位
return MAXTEMP; //返回被删除的根结点
}
最后是对已知序列建立成最大堆
我们先将序列一个一个存入堆中(此时是没有最大堆的特性的,只是一个完全二叉树)
然后定位到最后一个有儿子结点的父亲结点,即 i=size/2;
从这个结点开始进行调整儿子结点的位置;该结点调整完就往前挪;即i–
一个一个父亲结点的调整,直到调到根结点为止;最大堆建立完成。
需要一个调整的函数 percdown
首先定义一个temp 令它等于父亲结点 date[p] (p为根节点) 当父亲结点大于最大的儿子结点时,顺序正确;直接break
对于父亲结点比儿子结点小的情况,交换位置 date[dad]=date[child]
/*当给定一个已知序列,把该序列(未排序)建设成一个最大堆
可以利用插入函数一个一个插入,只是时间复杂度较大 O(NlogN)
在这里用另一个方式,可以在线性时间复杂度下完成
先按序列顺序建立出完全二叉树;接着调整各结点位置*/
void percdown(Maxheap *t,int p) //该函数可以调整一个子堆为最大堆 p是目标子堆的根结点
{
int dad,child,temp;
temp=t->Date[p]; //取出根结点值
for(dad =p;dad*2<=t->Size;dad=child)
{
child=dad*2;
if(child+1<=t->Size&&t->Date[child]<t->Date[child+1])
child+=1; //选出大儿子
if(temp>t->Date[child]) break;
else
t->Date[dad]=t->Date[child];
}
t->Date[dad]=temp;
}
void Buildheap(Maxheap *t)
{
int i;
for(i=t->Size/2;i>0;i--) //从最后一个子结点的父结点开始调整到根结点(i==1)
percdown(t,i);
}