索引优先队列

一、简介

在很多应用中,允许用例对已经进入优先队列中的元素非常有必要。

一个简单的实现方法是对每个元素关联一个索引

 

索引优先队列API:

 

二、实现

 通过对普通优先队列的实现进行拓展来实现索引优先队列。

思路:

(1)增加数组keys用来保存优先队列元素(item or key)

(2)pq数组则改用于保存索引(pq[i] = k,k为索引)

    这里的pq数组仍然保持堆有序,即pq[1]所对应的元素(keys[pq[1]])大于或等于pq[2]、pq[3]所对应的元素(keys[pq[2]]、keys[pq[3]])。

(3)增加数组qp,用于保存pq的逆序。

    如果pq[i] = k,则qp[k] = i,也就是pq[qp[k]] = k。

    如果k不在队列之中,则qp[k] = -1。

 

代码实现:

package com.qiusongde;

import java.util.NoSuchElementException;

public class IndexMinPQ<Key extends Comparable<Key>> {
    
    /*
     * k is index(0,maxN-1)
     * pq[i] = k means the ith node in the heap is keys[k]
     * qp[k] = i means keys[k] is the ith node in the heap
     * qp[k] = -1 if k(index) is not in the Priority Queue
     * 
     */
    private Key[] keys;//items with priorities
    private int[] pq;//binary heap using 1-based indexing
    private int[] qp;//inverse: qp[pq[i]] = pq[qp[i]] = i
    private int n;//number of elements on PQ
    private int maxN;
    
    public IndexMinPQ(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 static void main(String[] args) {
        // insert a bunch of strings
        String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" };

        IndexMinPQ<String> pq = new IndexMinPQ<String>(strings.length);
        for (int i = 0; i < strings.length; i++) {
            pq.insert(i, strings[i]);
        }

        // delete and print each key
        while (!pq.isEmpty()) {
            int i = pq.delMin();
            StdOut.println(i + " " + strings[i]);
        }
        StdOut.println();


    }

 

 

3 best
0 it
6 it
4 of
8 the
2 the
5 times
7 was
1 was
9 worst

 

 

三、应用

 多向归并问题:

将多个有序的输入流归并成一个有序的输入流。使用优先队列,无论输入有多长都可以将这些数据读入并归并。

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 @ 2017-04-19 21:53  我是老邱  阅读(1910)  评论(0编辑  收藏  举报