【数据结构与算法分析】第六章 优先队列(堆)
一般来说,短的作业应尽可能快的结束,则已经被运行的作业当中这些短作业应拥有优先权,此外,有些作业虽不短小但也很重要,也应该拥有优先权。
1.模型
优先队列允许下列两种操作:
Insert(插入),等价于入队,即插入内容
DeleteMin(删除最小者),等价于出队,它的工作是找出、返回和删除优先队列中的最小元素。
2.二叉堆
二叉堆,堆的一种特殊的堆,一般用于实现优先队列,此节中将二叉堆称为堆
二叉堆的性质:结构性和堆序性
2.1结构性质
基本概念:
满二叉树:一棵被完全填满的二叉树
完全二叉树:若设二叉树的深度为h,除第h 层外,其它各层(1~h-1) 的结点数都达到最大个数,第h 层所有的结点都连续集中在最左边,这就是完全二叉树
注意:满二叉树是特殊的完全二叉树,二叉堆为满二叉树或完全二叉树
此完全二叉树的数组实现为:
A | B | C | D | E | F | G | H | I | J | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在(2i+1)上,父亲在i/2上
优先队列的声明:
#ifndef _BinHeap_H
struct HeapStruct;
typedef struct HeapStruct *PriorityQueue;
PriorityQueue Initialize(int MaxElements);
void Destroy(PriorityQueue H);
void MakeEmpty(PriorityQueue H);
void Insert(ElementType X,PriorityQueue H);
ElementType DeleteMin(PriorityQueue H);
ElementType FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
int Isfull(PriorityQueue H);
#endif
struct HeapStruct
{
int Capacity;//最大值的整数
int Size;//当前堆的大小
ElementType *Elements;//一个数组
}
堆数据结构组成:
一个数组(不管关键字是什么类型),一个代表最大值的整数和当前堆的大小
2.2堆序性质
使操作被快速执行的性质是堆序性。
堆序性:在一个堆中,对于每一个节点X,X的父节点的关键字小于或等于X的关键字,根节点除外(无父节点),即父节点均小于或等于子节点
如图,只有左边为堆
创建一个优先队列:
PriorityQueue Inialize(int MaxElements)
{
PriorityQueue H;
if(MaxElements < MinPQSize)
Error("queue size is too small");
H=malloc(sizeof(struct HeapStruct));//分配堆的空间
if(H==NULL)
FatalError("out of space");
H->Elements=malloc((MaxElements + 1)*sizeof(ElementType));//分配数组的空间,加1是设置哨兵防止出界
if(H->Elements==NULL)
FatalError("out of space");
H->Capacity=MaxElements;
H->Size=0;
H->Elements[0]=MinData;
return H;
}
2.3基本的堆操作
2.3.1 Insert插入
为将一个元素X插入到堆中,在下一个空闲位置创建一个空穴,否则该堆将不是完全树。如果X可以放在空穴中而并不破坏堆的序,那么插入成功。否则,我们把空穴的父节点上的元素移入该空穴,这样空穴就朝根的方向行一步
继续该过程直到X能被放入空穴中为止
插入到一个二叉堆的过程:
void Insert(ElementType X,PriorityQueue H)
{
int i;
if(IsFull(H))
{
Error("Priority queue is full");
return;
}
for(i=++H->Size;H->Elements[i/2]>X;i/=2)
H->Elements[i]=H->Elements[i/2];
H->Elements[i]=X;
}
2.3.2DeleteMin(删除最小元)
(1)最小元在跟节点,删除后在根节点会产生一个空穴,由于现在堆少了一个元素,则堆最后一个元素X必须移到堆中的某个位置,如图
(2)将空穴的两子节点中较小者移入空穴,这样就把空穴向下推了一层,如图
(3)重复第二步,直到X能被放入空穴中
在二叉堆中执行DeleteMin的函数:
ElementType DeleteMin(PriorityQueue H)
{
int i,child;
ElementType MinElement,LastElement;
if(IsEmpty(H))
{
Error("Priority queue is empty");
return H->Elements[0];
}
MinElement=H->Elements[1];
LastElement=H->Elements[H->Size--];
for(i=1;i*2<=H->Size;i=child)
{
child =i*2;
if(child!=H->Size&&H->Elements[child+1]<H->Elements[child])
child++;
if(LastElement>H->Elements[child])
H->Elements[i]=H->Elements[child];
else
break;
}
H->Elements[i]=LastElement;
return MinElement;
}