二叉堆

一、优先队列

  • 当一颗二叉树的每个结点都大于等于它的两个子结点时,称堆有序。根节点是堆有序的二叉树中的最大结点。
  • 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储(不使用数组的第一个位置0)
  • 上浮:某个节点比他的父节点大,则需要通过交换它和它的父节点
  • 下沉:当某个节点比他的两个子节点要小,则通过将他和它的两个子节点中的较大者交换来恢复堆。
  • 插入元素:将新元素添加到数组末尾,增加堆的大小,并让这个新元素上浮到合适的位置
  • 删除最大元素:从数组顶端删去最大元素并将数组的最后一个元素放到顶端,减小堆的大小并让这个元素下沉到合适的位置
package 二叉排序树;
//基于堆的优先队列
public class MaxPQ {

    private int[] num;
    private int N=0;

    public MaxPQ(int maxN) {
        num=new int[maxN+1];
    }
    public int size(){
        return N;
    }
    public boolean empty(){
        return N==0;
    }
    public void  insert(int x){
        num[++N]=x;
        swim(N);
    }

    private void swim(int n) {
        while (n>1&& less(n/2,n)){
            exch(n/2,n);
            n/=2;
        }
    }
    public int delMax(){
        int max=num[1];
        exch(max,N--);//把最后一个节点放到顶端
        num[N+1]=-1;
        sink(1);//保持堆的有序性
        return max;
    }
    private void sink(int n){
        while (n*2<N){
            int j=2*n;
            if(j<N&&less(j,j+1))j=j+1;
            if(!less(n,j)){
                break;
            }else exch(j,n);
            n=j;
        }
    }
    public boolean  less(int x,int y){
        return num[x]-num[y]<0;
    }
    public void exch(int x,int y){
        int temp=num[x];
        num[x]=num[y];
        num[y]=temp;
    }

}

二、索引优先队列

  • keys的作用是存储对象的引用,我们将每个对象存储在与之相关的整数作为下标的位置中,keys存储的对象不一定在数组中连续存放。
  • pq存储是与对象相关的整数值,注意数组pq是连续存放的。此时pq作为优先队列。
  • 为了能够快速找到pq中元素值对应的下标,我们需要额外设置一个数组qp,它的作用是存储与对象相关的整数在pq数组中的下标,并在上浮和下沉的过程中同时维护它。
package 二叉排序树;

import java.util.NoSuchElementException;

public class IndexPQ<Key extends Comparable<Key>> {

    private Key[] keys;//索引保存的值
    private int[] pq;//优先队列,绑定的是索引信息
    private int[] qp;//反向绑定 qp[pq[i]] = pq[qp[i]] = i
    private int n;//PQ大小
    private int maxN;

    public IndexPQ(int maxN) {

        if(maxN < 0)
            throw new IllegalArgumentException("The size of IndexMinPQ should larger than 0");

        this.maxN = maxN;
        keys = (Key[]) new Comparable[maxN + 1];
        pq = new int[maxN + 1];
        qp = new int[maxN + 1];
        for(int i = 0; i <= maxN; i++)
            qp[i] = -1;
        n = 0;
    }

    public boolean isEmpty() {
        return n == 0;
    }

    public int size() {
        return n;
    }

    public boolean contains(int k) {
        if(k < 0 || k >= maxN)
            throw new IndexOutOfBoundsException();
        return qp[k] != -1;
    }

    public void insert(int k, Key key) {

        if (k < 0 || k >= maxN)
            throw new IndexOutOfBoundsException();
        if (contains(k))
            throw new IllegalArgumentException("index is already in the priority queue");

        n++;
        qp[k] = n;
        pq[n] = k;
        keys[k] = key;
        swim(n);

    }

    public Key min() {

        if(n == 0)
            throw new NoSuchElementException("IndexMinPQ underflow");

        return keys[pq[1]];

    }

    public int minIndex() {

        if(n == 0)
            throw new NoSuchElementException("IndexMinPQ underflow");

        return pq[1];
    }

    public int delMin() {

        if(n == 0)
            throw new NoSuchElementException("IndexMinPQ underflow");

        int indexOfMin = pq[1];

        exch(1, n--);
        sink(1);
        keys[pq[n+1]] = null;
        qp[pq[n+1]] = -1;

        return indexOfMin;
    }

    public void delete(int i) {

        if (i < 0 || i >= maxN)
            throw new IndexOutOfBoundsException();
        if (!contains(i))
            throw new NoSuchElementException("index is not in the priority queue");

        int index = qp[i];
        exch(index, n--);
        swim(index);
        sink(index);
        keys[i] = null;
        qp[i] = -1;

    }

    public void changeKey(int i, Key key) {

        if (i < 0 || i >= maxN)
            throw new IndexOutOfBoundsException();
        if (!contains(i))
            throw new NoSuchElementException("index is not in the priority queue");

        keys[i] = key;
        swim(qp[i]);
        sink(qp[i]);

    }

    /***************************************************************************
     * General helper functions.
     ***************************************************************************/
    private boolean greater(int i, int j) {
        return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
    }

    private void exch(int i, int j) {
        int swap = pq[i];
        pq[i] = pq[j];
        pq[j] = swap;
        qp[pq[i]] = i;
        qp[pq[j]] = j;
    }


    /***************************************************************************
     * Heap helper functions.
     ***************************************************************************/
    private void swim(int k) {
        while (k > 1 && greater(k/2, k)) {
            exch(k, k/2);
            k = k/2;
        }
    }

    private void sink(int k) {
        while (2*k <= n) {
            int j = 2*k;
            if (j < n && greater(j, j+1)) j++;
            if (!greater(k, j)) break;
            exch(k, j);
            k = j;
        }
    }


}

三、多项归并

  • 将多个有序的输入归并成一个有序的输出流
public class Multiway { 

    // This class should not be instantiated.
    private Multiway() { }

    // merge together the sorted input streams and write the sorted result to standard output
    private static void merge(In[] streams) {
        int n = streams.length;
        IndexMinPQ<String> pq = new IndexMinPQ<String>(n);
        for (int i = 0; i < n; i++)
            if (!streams[i].isEmpty())
                pq.insert(i, streams[i].readString());

        // Extract and print min and read next from its stream. 
        while (!pq.isEmpty()) {
            StdOut.print(pq.minKey() + " ");
            int i = pq.delMin();
            if (!streams[i].isEmpty())
                pq.insert(i, streams[i].readString());
        }
        StdOut.println();
    }


    /**
     *  Reads sorted text files specified as command-line arguments;
     *  merges them together into a sorted output; and writes
     *  the results to standard output.
     *  Note: this client does not check that the input files are sorted.
     *
     * @param args the command-line arguments
     */
    public static void main(String[] args) {
        int n = args.length;
        In[] streams = new In[n];
        for (int i = 0; i < n; i++)
            streams[i] = new In(args[i]);
        merge(streams);
    }
}

 

posted @ 2022-01-12 17:01  forever_fate  阅读(64)  评论(0)    收藏  举报