优先队列(堆)

来源:互联网 发布:独立域名 编辑:程序博客网 时间:2024/05/21 16:32


优先队列(priority model)模型

  insert:等价enqueue(入队)操作

  deleteMin:它的工作是找出、返回并删除优先队列中最小的元素,等价dequeue(出队)操作

优先队列基本模型:

  

优先队列可以用外部排序。在贪婪算法(greedy algorithm)的实现方面优先队列也是很重要的,该算法通过反复求出最小元来进行操作。


一些简单的实现

  1)使用一个简单链表在表头以O(1)执行插入操作,并变量该链表以删除最小元,这需要O(N)时间。

  2)始终让链表保持排序状态,这使得插入代价高昂(O(N))而deleteMin花费低廉(O(1))。方法1比方法2好。

  3)使用二叉查找树,它对这两种操作(插入、删除)的平均运行时间都是O(logN)。尽管插入是随机的,而删除则不是,但这个结论还是成立的。


二叉堆(binary heap)

  就是平时所说的堆(heap)。性质:结构性和堆序性。堆的操作必须到堆的所有性质都被满足时才能终止。


结构性质

  堆是一颗被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树(complete binary tree)。


一颗高为h的完全二叉树有2h到2h+1-1个节点。这意味着完全二叉树的高是小于等于logN的整数值,显然它是O(logN)。

完全二叉树的数组实现:


一个堆结构将由一个(Comparable对象的)数组和一个代表当前堆大小的整数组成。类架构如下:

public class BinaryHeap<AnyType extends Comparable<? super AnyType>> {public BinaryHeap(){}public BinaryHeap(int capacity){}public BinaryHeap(AnyType[] items){}public BinaryHeap(AnyType x){}public AnyType findmin(){}public AnyType deleteMin(){}public boolean isEmpty(){}public void makeEmpty(){}private static final int DEFAULT_CAPACITY = 10;private int currentSize;  //堆中元素数量private AnyType[] array;  //堆数组private void percolateDown(int hole){}private void buildHeap(){}private void enlargeArray(int newSize){}}


堆序性质(heap-order property)

  让操作快速执行的性质是堆序性质。在一个堆中,对于每一个节点X,X的父亲中的关键字小于(或等于)X中的关键字,根节点除外(它没有父亲)。


基本的堆操作

insert(插入)

  为将一个元素X插入到堆中,我们在下一个可用位置创建一个空穴,否则该堆将不是完全树。如果X可以放在该空穴中而并不破坏堆的序,那么插入完成。否则,我们把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上冒一步。继续该过程直到X能被放入空穴中为止。这种策略叫做上滤(precolate up)。


插入到一个二叉堆的过程:

    /**     * Insert into the priority queue,maintaining heap order.     * Duplicates are allowed     * @param x the item to insert     */    public void insert(AnyType x){    if(currentSize==array.length-1){    enlargeArray(array.length*2+1);    }        //Percolate up    int hole = ++currentSize;    for(;hole>1 && x.compareTo(array[hole/2])<0;hole/=2){    array[hole] = array[hole/2];    }    array[hole] = x;    }


deleteMin(删除最小元)

  当删除一个最小元时,要在根节点建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素X必须移动到该堆的某个地方。如果X可以被放到空穴中,那么deleteMin完成。不过这一般不太可能,因此我们将空穴的两个儿子中较小者移入空穴,这样就把空穴向下推了一层。重复该步骤直到X可以被放入空穴中。因此,我们的做法是将X置入沿着从根开始包含最小儿子的一条路径上一个正确的位置。这种策略叫做下滤(percolate down)。

在二叉堆中执行deleteMin的方法:

    /**     * Remove the smallest item from the priority queue     * @return the smallest item,or throw UnderflowException,if empty     */    public AnyType deleteMin(){    if(isEmpty()){    throw new UnderflowException();    }        AnyType minItem = findMin();    array[1] = array[currentSize--];    percolateDown(1);    return minItem;    }        /**     * Internal method to percolate down in the heap     * @param hole the index at which the perolate begins     */    private void percolateDown(itn 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;    }


decreaseKey(降低关键字的值)

  decreaseKey(p,)操作降低在位置p处的项的值,降值的幅度为正的量。由于这可能破坏堆序性质,因此必须通过上滤对堆进行调整。

increaseKey(增加关键字的值)

  increateKey(p,)操作增加在位置p处的项的值,增值的幅度为正的量。这可以用下滤来完成。

delete(删除)

  delete(p)操作删除堆中位置p上的节点。该操作通过首先执行decreaseKey(p,无穷)然后再执行deleteMin()来完成。当一个进程被用户中止(而不是正常终止)时,它必须从优先队列中除去。

buildHeap(构建堆)

  

    /**     * Construct the binary heap given an array of items     */    public BinaryHeap(AnyType[] items){    currentSize = items.length;    array = (AnyType[])new Comparable[(currentSize+2)*11/10];    int i = 1;    for(AnyType item:items){    array[i++] = item;    }    buildHeap();    }    /**     * Establish heap order property from an arbitrary     * arrangment of items. Runs in linear time     */    private void buildHeap(){    for(int i=currentSize/2;i>0;i--){    percolateDown(i);    }    }

包含2h+1 - 1 个节点,高为h的理想二叉树(perfect binary tree)的节点的高度的和为2h+1 - 1 - (h+1)。




  

0 0