算法_优先队列

  优先队列是一种数据结构,它支持删除最大元素和插入元素.可以利用优先队列实现对于数组的高效排序.

  数据结构二叉堆能够很好的实现优先队列的操作,在二叉堆的数组中,每个节点都大于等于它的子节点,这种情况被称为堆有序.而根节点将是堆有序的二叉树中的最大结点.在一个二叉堆中,位置k的节点的父节点的位置为[k/2],而它的两个子节点的位置则分别为2k,2K+1.这样在不使用指针的情况下,我们可以通过计算树的索引实现在树中的上下移动,a[k]向上一层就是a[k/2],向下一层就是令k等于2k或是2k+1.

  下面是基于堆的优先队列的基本实现:

public class MaxPQ<Key extends Comparable<Key>> {
    private Key[] pq;
    private int N;
    public MaxPQ(int maxN) {
        pq=(Key[])new Comparable[maxN+1];
    }
    public boolean isEmpty() {
        return N==0;
    }
    public int size() {
        return N;
    }
    public void insert(Key v) {
        pq[++N]=v;
        swim(N);
    }
    private void swim(int k )/*在堆底插入元素的时候,所对应的上浮操作.*/ {
        while(k>1&&less(k/2,k)) {
            exch(k/2,k);
            k=k/2;
        }
    }
    public Key delMax() {
        Key max=pq[1];
        exch(1,N--);    //将其和最后一个结点交换
        pq[N+1]=null;    //防止对象游离
        sink(1);        //回复堆的有序性
        return max;  
    }
    private void sink(int i) {
        while(2*i<=N) {
            int j=2*i;
            if(j<N&&less(j,j+1)) j++;
            if(!less(i,j)) break;
            exch(i,j);
            i=j;
        }
    }
    public void exch(int i, int k) {
        Key t=pq[i];
        pq[i]=pq[k];
        pq[k]=t;
    }
    private boolean less(int i, int k) {
        return pq[i].compareTo(pq[k])<0;
    }
}

  对于一个N个元素的基于堆的优先级队列,插入元素操作只需不超过lgN+1次比较,删除最大元素的操作只需不超过2lgN次比较.

  通过基于二叉堆的优先队列,可以实现对于数组的排序,开始的时候我们只需要扫描数组中的一半的元素,因此我们可以跳过大小为1的子堆,最后我们在位置1上调用sink方法,扫描结束.堆排序的实现算法如下:

public static void sort(Comparable[] a) {
        int N=a.length;
        for(int k=N/2;k>=1;k--) {
            sink(a,k,N);
        }
        while(N>1) {
            exch(a,1,N--);
            sink(a,1,N);
        }
    }

  这段代码中,for循环构造了堆,然后while循环将最大的元素a[1]和a[N]交换,然后如此重复直到堆变空,第二阶段将堆中的最大元素删除,然后放入堆缩小后数组空出来的位置.这种算法被称为堆排序算法.将N个元素排序堆排序只需少于2NlgN+2N次比较.(2N来自于堆构造,2NlgN来自于每次下沉操作最大可能需要的比较).

posted @ 2016-07-06 10:06  hlhdidi  阅读(212)  评论(0编辑  收藏  举报