priority queue 优先队列

来源:互联网 发布:吉列剃须刀哪款好 知乎 编辑:程序博客网 时间:2024/05/21 12:48

优先队列是允许至少下列两种操作的数据结构,insert和deleteMin,deleteMin是找出,返回并删除优先队列中最小的元素,insert操作类似enqueue(入队),而deleteMin则是dequeue(出队),可用于外部排序,我们可以使用一个简单的链表,在表头以O(1)执行插入操作,并遍历该链表来删除最小元素,这需要O(N)时间;另一种方法是始终让链表保持排序的状态,然而这使得插入代价高昂(O(N))而deleteMin花费低廉O(1)。

另一种实现的方式是使用二叉查找树,它对插入及删除最小元的操作都是O(logN).

堆是一棵被完全填满的二叉树,底层上的元素从左填到右,这样的树被称为完全二叉树.


完全二叉树如此有规律可以使用数组表示而不用使用链.


对于数组中任意位置元素i,其左二子在位置2i上,右儿子在位置2i+1上,其父亲节点位于i/2上.

以上是堆的结构性质,以下为堆的堆序性质:

由于我们要找出最小元,因此最小元一定在根节点上,,如果我们考虑任意子树也是个节点,那么任意节点应该小于它的所有后裔.

所以对于所有的节点X,X的父亲节点中的关键字总是小于或者等于X中的关键字.

为了将X节点插入到堆中,我们可以在树的可用空间插入一个空的穴,把X放入穴中,如果可以保持堆序性,则插入完成,否则把X的父亲节点插入到该穴位置,将空穴往上冒,

知道冒进到满足堆的堆序性质为止,这种插入的策略叫上滤(percolateUp).





上述示例演示了将14插入到完全二叉树中的上滤过程.

public void insert(AnyType x){int hole = ++currentSize;for(;hole>1&&x.compareTo(array[hole/2])<0;hole/2){array[hole]=array[hole/2];}array[hole] = x;}
找出堆中的最小元并不难,难的删除它,当删除了最小元后,堆中的最后一个元素必须移动到堆中的某个地方,若是可以直接放到空穴中,deleteMin自然完成,事实上并不轻松,因此我们将空穴的两个儿子中的较小者放到空穴中,将空穴向下移动一层,直到最后一个元素可以被放到空穴中.

下例演示了删除最小元后,树的变化:






当删除最小元13后,在根节点建立了空穴,31不可以放入空穴,因为14>31,因此只能讲空穴的两个儿子中的较小者14放入空穴,空穴向下滤(percolateDown),31依然不能放入,因为比19大,将19放入,31依然不能放入,将26放入,空穴被滤到树底,再将31放入,完成.

code:

private void percolateDown(int hole){int child;AnyType tmp = array[hole];for(;hole*2<=currentSize;hole=child){child =hole*2;if(child!=currentSize&&array[child+1].compareTo(array[child]<0){child++;}if(array[child].compareTo(tmp)<0){array[hole] = array[child];}else{break;}}array[hole] = tmp;}

So,that is the basic concept.



0 0