堆,又称为优先队列。虽然名为优先队列,但堆并不是队列。堆和队列是两种不同的数据结构,堆是树态的,队列是线性的。在队列中,我们可以向队列添加元素,取出的时候是按照进入队列的先后顺序取出元素的,先进先出;而在堆中,却不是按照元素添加的先后顺序,而是按照元素的优先级取出元素
二叉堆的特性:
1.父节点的键值总是优先于任何一个子节点的键值;
2.左右子树都是一个二叉堆
二叉堆的操作:
1)上浮:就是在末尾哪里插入数据之后,根据这个数据的优先级向上自动,比如插入21
2)下浮:就是取出最大优先级之后,要一层一层往下找出,例如取出13
例如上面的删除操作,最后一步的时候,26向上移动了,这就需要选择最后面的数据31来顶替他的位置。
二叉堆可以通过定义一个数组来实现。例如:
堆顶下标从1开始:
parent(i) = i/2;
leftChild = 2 *i;
rightChild = 2 *i+1;
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define DUISIZE 100
//插入数据
//插入最末尾,一层一层往上浮
void Insert(int date,int duidate[])
{
int i=0;
if(duidate[0]>=(DUISIZE-1)){
printf("no memory");
return;
}
duidate[0]++;//插入计数+1
if(duidate[0]==1){//表示插入第一个数据
duidate[1]=date;
return;
}
//如果当前父节点比插入的数据要大
//那就继续往上浮
for(i=duidate[0];duidate[i/2]>date&&i>0;i=i/2){
duidate[i]=duidate[i/2];
}
//来到这里说明已经找到插入date 的位置了
duidate[i]=date;
}
//取出数据
//策略就是把最后一个数据,补到空白的地方
int GetDate(int duidate[])
{
int i=0,child=0;
//取出优先级最高的数据
int returndate=duidate[1];
//取出队列中最后的一个数据,并确计数-1
int lastdate=0;
if(duidate[0] ==0) return 0;//没有数据
lastdate=duidate[duidate[0]];
duidate[0]--;
for(i=1;i*2<=duidate[0];i=child){
//判断子的大小
child=i*2;
//child!=duidate[0]这个判断条件是防止末尾
//哪里只有一个子节点的情况
if(child!=duidate[0]&&duidate[child]>duidate[child+1]){
//说明有节点比较小
child++;
}
if(lastdate>duidate[child]){
duidate[i]=duidate[child];//子节点较小的数网上移
}else{ //如果最后的数据比较小,那就直接返回了
break;
}
}
duidate[i]=lastdate;
return returndate;
}
void main(void)
{
int maindate[DUISIZE],i=0,temp=0;
int k[10]={13,55,74,21,5,69,44,23,41,99};
memset(maindate,0,DUISIZE*sizeof(int));
for(i=0;i<10;i++){
Insert(k[i],maindate);
}
for(i=0;i<10;i++){
temp=GetDate(maindate);
printf("%2d ",temp);
}
printf("\n");
}