什么是堆
优先队列:特殊的“队列”,取出元素的顺序是按照元素的优先级大小,而不是进入队列的先后顺序。
优先队列可以用数组、链表、有序数组、有序链表实现,也可以用完全二叉树表示。其中,完全二叉数的每个结点都比其子树的数值大。如下图所示:
堆的抽象数据类型描述
类型名称:最大堆
数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值。
操作集:创建一个空的最大堆、判断最大堆是否已满、将元素插入最大堆、判断最大堆是否为空、返回最大堆的最大元素。
最大堆的创建
typedef struct HeapStruct "MaxHeap";
struct HeapStruct{
ElementType *Elements; //存储堆元素的数组
int Size; //堆的当前元素个数
int Capacity; //堆的最大容量
};
MaxHeap Create(int MaxSize){
MaxHeap H = malloc(sizeof(struct HeapStruct));
H->Elements = malloc((MaxSize+1)*sizeof(ElementType));
//加1是因为数组是从下标为1开始存放的
H->Size=0;
H->Capacity = MaxSize;
H->Elements[0]=MaxData;
//MaxData作为哨兵
return H;
}
最大堆的插入
插入数按照完全二叉树的规则插入,如果插入之后比其父结点大,则和父结点换位置,换位置之后如果还比其父结点大,再换位置。时间复杂度为logN
void Insert(MaxHeap H, ElementType item){
int i;
if(IsFull(H)){
printf("最大堆已满");
return;
}
i = ++H->Size;
//i就是插入点的位置
for(;H->Elements[i/2]<item;i/=2){
//H->Elements[i/2]就是该插入点的父结点的值
H->Elements[i]=H->Elements[i/2];
}
H->Elements[i]=item;
}
最大堆的删除
ElementType DeleteMax(MaxHeap H){
//删除最大值
int Parent, Child;
ElementType MaxItem, temp;
if(IsEmpty(H)){
printf("最大堆为空");
return;
}
MaxItem = H->Elements[1];
temp = H->Elements[H->Size--];
for(Parent=1;Parent*2<=H->Size;Parent=Child){
//Parent*2<=H->Size 判别是否有左儿子
Child = Parent*2;//Child 指向左儿子
if((Child!=H->Size)&&
(H->Elements[Child]<H->Elements[Child+1])){
//Child!=H->Size 表示左儿子不是最后一个数,
//则必有右儿子,接下来才能判断左右儿子的大小
Child ++;
}
//上一步的目的就是找出左右儿子中较大者的位置
if(temp >= H->Elements[Child]){
break;
}
//上一步的意思是temp比左右儿子中的较大数还大,
//就不做操作了
else{
H->Elements[Parent] = H->Elements[Child];
}
//反之,对换位置
}
H->Elements[Parent] = H->Elements[Child];
return MaxItem;
}
最大堆的建立
将已知存在的N个元素按最大堆的要求存放在一个一维数组中。
方法一:通过插入操作,将N个元素一个个地插入到空最大堆。
方法二:将N个元素按顺序输入,先满足完全二叉树的结构特性。然后调整位置,满足最大堆的有序特性。