优先队列(priority queue)
优先队列允许至少下列两种操作的数据结构:
- Insert
- DeleteMin : 找出、返回、删除优先队列中最小的元素
实现
- 简单链表
- 二叉查找树
- 二叉堆(binary heap)
二叉堆
结构性
堆是一颗被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右的填入,这样的树被称为完全二叉树
一颗高为h的完全二叉树有2^h到2^(h+1)-1个节点。
根据完全二叉树的特性,我们可以用数组来表示完全二叉树:- 对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)中,它的父亲则在位置(i/2)上。
堆序性
在一个堆中,对于每一个节点X,X的父亲中的关键字小于(或等于)X中的关键字,根节点除外。(最小堆情况)
基本的堆操作
Insert
- 插入新节点时,在下一个空闲位置创建一个空穴,否则该堆将不满足其结构性——完全二叉树的性质。
- 如果被插入的节点可以放在该空穴而且不破坏该堆的堆序性,则插入完成。如果被插入的节点破坏了堆序性质,我们采取上滤(percolate up)的策略来使其找到正确的位置。
- 上滤过程图示:
(图) - 代码实现
void insert(int X,PriorityQueue H)
{
int i;
if(IsFull(H))
{
printf("the 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;//将元素插入到正确位置
}
deleteMin
- 找到最小元(根节点),删除,此时堆中产生一个空穴。
- 将空穴的两个儿子中的较小者移入空穴,以保持堆序性。
- 重复步骤2,直到堆中最后一个元素x被放入空穴。
- 与上滤对应,这个过程称为下滤(percolate down)。
- 下滤图示:
(图) - 代码实现:
int DeleteMin(PriorityQueue H)
{
int i,Child;
int MinElement,lastElement;
if(IsEmpty(H))
{
printf("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)
{
/** Find smaller Child */
Child=i*2;//从第一层开始比较最小节点,同时保证Child必为左子树索引
if(Child!=H->Size&&H->elements[Child+1]<H->elements[Child])
Child++;
//如果右子树比左子树小,返回右子树,否则返回左子树
//如果Child已经为最后一个节点的索引,直接返回
/** Percolate one level */
if(lastElement > H->elements[Child])
H->elements[i]=H->elements[Child];//空节点下滤
else break;//如果子树根节点比最后一个节点大,直接跳出循环
}
H->elements[i]=lastElement;//将空节点与最后一个节点交换
return MinElement;//返回堆中最小值
}