一、定义
1、二叉堆是一棵被完全填满的二叉树(除了底层,底层的元素从左到右依次填入);
2、二叉堆具有堆序性质(即具有最小权值的堆元素处在树根位置,父节点权值小于等于子节点的权值);
二、二叉堆实现
因为二叉堆的堆序性质,所有可用来实现按权值优先输出的优先队列。此外,因为二叉堆是满二叉树,所以当用数组来存储堆元素时,父子节点间有银行关系,若父节点在数组中的位置为i,则左子节点在数组中的位置为2*i,右子节点在数组中的位置为2*i+1,如下图所示:
三、二叉堆的基本操作
二叉堆的基本操作有入队(添加元素)、出队(删除最小元素),上滤,下滤;
入队:先假设新入队的元素插在最后面,然后根据二叉堆的堆序性质逐渐上滤,知道找到正确位置;
出队:因为具有最小权值的元素在树根出,所以要把树根元素出队,但是此时树根就空了,根据堆序性质,需要从左、右儿子中选择一个儿子填上,逐渐上滤,直到满足条件。
四、其他堆操作:
改变堆元素的权值:此时更新完元素权值后,同时需要更新元素所处堆位置,如果增大权值,则要执行下滤操作,降低权值,则需要执行上滤操作。
求第k小堆元素:执行出队操作k此,第k次出队的元素就是第k小的元素。
附录
#include<stdio.h>
#include<stdlib.h>
typedef struct HeapStruct* PriorityQueue;
struct HeapStruct{
int capacity;//堆的容量
int size;//现在堆的大小
int *element;//堆元素
};
PriorityQueue Initialize(int MaxElements);//初始化堆
void Insert(PriorityQueue H,int x);//插入堆元素
int DeleteMin(PriorityQueue H);//出堆
int IsEmpty(PriorityQueue H);
int IsFull(PriorityQueue H);
void DecreaseKey(PriorityQueue H,int position,int deta);
void IncreaseKey(PriorityQueue H,int position,int deta);
int IsEmpty(PriorityQueue H){
return H->size==0;
}
int IsFull(PriorityQueue H){
return H->size==H->capacity;
}
PriorityQueue Initialize(int MaxElement){
PriorityQueue H;
H=(PriorityQueue)malloc(sizeof(struct HeapStruct));
if(H==NULL)
printf("Out of space!!!");
H->size=0;
H->capacity=MaxElement;
H->element=(int*)malloc(sizeof(int)*(MaxElement+1));
if(H->element==NULL)
printf("Out of space!!!");
H->element[0]=-1000;
return H;
}
void Insert(PriorityQueue H,int x){
int i;
if(IsFull(H)){
printf("The binheap is full!!");
return;
}
H->size++;
for(i=H->size;i>1;i/=2){
if(H->element[i/2]>x)
H->element[i]=H->element[i/2];
else
break;
}
H->element[i]=x;
}
int DeleteMin(PriorityQueue H){
int min,last,i,child;
min=H->element[1];
last=H->element[H->size];
H->size--;
for(i=1;i*2<=H->size;i=child){
child=i*2;
if(child+1<=H->size&&H->element[child]>H->element[child+1])
child++;
if(H->element[child]<last)
H->element[i]=H->element[child];
else{
break;
}
}
H->element[i]=last;
return min;
}
//降低某个堆元素的权值,提高执行等级
void DecreaseKey(PriorityQueue H,int position,int deta){
H->element[position]-=deta;
int i=position;
int key=H->element[position];
while(H->element[i/2]>key){
H->element[i]=H->element[i/2];
i/=2;
}
H->element[i]=key;
}
//增加某个堆元素的权值,降低执行等级
void IncreaseKey(PriorityQueue H,int position,int deta) {
H->element[position]+=deta;
int i,child;
int key=H->element[position];
for(i=position;i*2<=H->size;i=child){
child=2*i;
if(child+1<=H->size&&H->element[child]>H->element[child+1])
child++;
if(H->element[i]>H->element[child])
H->element[i]=H->element[child];
else
break;
}
H->element[i]=key;
}
int main(){
int N,n,k,t;
PriorityQueue H;
scanf("%d",&N);//堆的容量
H=Initialize(N);//初始化堆
for(int i=1;i<=N;i++){
scanf("%d",&n);
Insert(H,n);
}
for(int i=1;i<=H->size;i++)
printf("%d ",H->element[i]);//将堆元素输出
printf("\n");
/*printf("\n请输入要查找的第k小的值(k<N):");
scanf("%d",&k);
for(int i=1;i<=k;i++)
t=DeleteMin(H);
printf("%d",t);*/
IncreaseKey(H,5,20);
for(int i=1;i<=H->size;i++)
printf("%d ",H->element[i]);//将堆元素输出
return 0;
}