| 1 | // License: GPL v3 or later courtesy of author Kevin Wayne
|
|---|
| 2 | package edu.princeton.cs.algs4;
|
|---|
| 3 |
|
|---|
| 4 | /* ************************************************************************
|
|---|
| 5 | * Compilation: javac IndexMinPQ.java
|
|---|
| 6 | * Execution: java IndexMinPQ
|
|---|
| 7 | *
|
|---|
| 8 | * Indexed PQ implementation using a binary heap.
|
|---|
| 9 | *
|
|---|
| 10 | *********************************************************************/
|
|---|
| 11 |
|
|---|
| 12 | import java.util.Iterator;
|
|---|
| 13 | import java.util.NoSuchElementException;
|
|---|
| 14 |
|
|---|
| 15 | public class IndexMinPQ<Key extends Comparable<Key>> implements Iterable<Integer> {
|
|---|
| 16 | private int N; // number of elements on PQ
|
|---|
| 17 | private int[] pq; // binary heap using 1-based indexing
|
|---|
| 18 | private int[] qp; // inverse of pq - qp[pq[i]] = pq[qp[i]] = i
|
|---|
| 19 | private Key[] keys; // keys[i] = priority of i
|
|---|
| 20 |
|
|---|
| 21 | @SuppressWarnings("unchecked")
|
|---|
| 22 | public IndexMinPQ(int NMAX) {
|
|---|
| 23 | keys = (Key[]) new Comparable[NMAX + 1]; // make this of length NMAX??
|
|---|
| 24 | pq = new int[NMAX + 1];
|
|---|
| 25 | qp = new int[NMAX + 1]; // make this of length NMAX??
|
|---|
| 26 | for (int i = 0; i <= NMAX; i++) qp[i] = -1;
|
|---|
| 27 | }
|
|---|
| 28 |
|
|---|
| 29 | // is the priority queue empty?
|
|---|
| 30 | public boolean isEmpty() { return N == 0; }
|
|---|
| 31 |
|
|---|
| 32 | // is k an index on the priority queue?
|
|---|
| 33 | public boolean contains(int k) {
|
|---|
| 34 | return qp[k] != -1;
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | // number of keys in the priority queue
|
|---|
| 38 | public int size() {
|
|---|
| 39 | return N;
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | // associate key with index k
|
|---|
| 43 | public void insert(int k, Key key) {
|
|---|
| 44 | if (contains(k)) throw new NoSuchElementException("item is already in pq");
|
|---|
| 45 | N++;
|
|---|
| 46 | qp[k] = N;
|
|---|
| 47 | pq[N] = k;
|
|---|
| 48 | keys[k] = key;
|
|---|
| 49 | swim(N);
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | // return the index associated with a minimal key
|
|---|
| 53 | public int minIndex() {
|
|---|
| 54 | if (N == 0) throw new NoSuchElementException("Priority queue underflow");
|
|---|
| 55 | return pq[1];
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | // return a minimal key
|
|---|
| 59 | public Key minKey() {
|
|---|
| 60 | if (N == 0) throw new NoSuchElementException("Priority queue underflow");
|
|---|
| 61 | return keys[pq[1]];
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | // delete a minimal key and returns its associated index
|
|---|
| 65 | public int delMin() {
|
|---|
| 66 | if (N == 0) throw new NoSuchElementException("Priority queue underflow");
|
|---|
| 67 | int min = pq[1];
|
|---|
| 68 | exch(1, N--);
|
|---|
| 69 | sink(1);
|
|---|
| 70 | qp[min] = -1; // delete
|
|---|
| 71 | keys[pq[N+1]] = null; // to help with garbage collection
|
|---|
| 72 | pq[N+1] = -1; // not needed
|
|---|
| 73 | return min;
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | // return key associated with index k
|
|---|
| 77 | public Key keyOf(int k) {
|
|---|
| 78 | if (!contains(k)) throw new NoSuchElementException("item is not in pq");
|
|---|
| 79 | else return keys[k];
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | // change the key associated with index k
|
|---|
| 83 | public void change(int k, Key key) {
|
|---|
| 84 | changeKey(k, key);
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | // change the key associated with index k
|
|---|
| 88 | public void changeKey(int k, Key key) {
|
|---|
| 89 | if (!contains(k)) throw new NoSuchElementException("item is not in pq");
|
|---|
| 90 | keys[k] = key;
|
|---|
| 91 | swim(qp[k]);
|
|---|
| 92 | sink(qp[k]);
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | // decrease the key associated with index k
|
|---|
| 96 | public void decreaseKey(int k, Key key) {
|
|---|
| 97 | if (!contains(k)) throw new NoSuchElementException("item is not in pq");
|
|---|
| 98 | if (keys[k].compareTo(key) <= 0) throw new RuntimeException("illegal decrease");
|
|---|
| 99 | keys[k] = key;
|
|---|
| 100 | swim(qp[k]);
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | // increase the key associated with index k
|
|---|
| 104 | public void increaseKey(int k, Key key) {
|
|---|
| 105 | if (!contains(k)) throw new NoSuchElementException("item is not in pq");
|
|---|
| 106 | if (keys[k].compareTo(key) >= 0) throw new RuntimeException("illegal decrease");
|
|---|
| 107 | keys[k] = key;
|
|---|
| 108 | sink(qp[k]);
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | // delete the key associated with index k
|
|---|
| 112 | public void delete(int k) {
|
|---|
| 113 | if (!contains(k)) throw new NoSuchElementException("item is not in pq");
|
|---|
| 114 | int index = qp[k];
|
|---|
| 115 | exch(index, N--);
|
|---|
| 116 | swim(index);
|
|---|
| 117 | sink(index);
|
|---|
| 118 | keys[k] = null;
|
|---|
| 119 | qp[k] = -1;
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 | /**************************************************************
|
|---|
| 124 | * General helper functions
|
|---|
| 125 | **************************************************************/
|
|---|
| 126 | private boolean greater(int i, int j) {
|
|---|
| 127 | return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | private void exch(int i, int j) {
|
|---|
| 131 | int swap = pq[i]; pq[i] = pq[j]; pq[j] = swap;
|
|---|
| 132 | qp[pq[i]] = i; qp[pq[j]] = j;
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 |
|
|---|
| 136 | /**************************************************************
|
|---|
| 137 | * Heap helper functions
|
|---|
| 138 | **************************************************************/
|
|---|
| 139 | private void swim(int k) {
|
|---|
| 140 | while (k > 1 && greater(k/2, k)) {
|
|---|
| 141 | exch(k, k/2);
|
|---|
| 142 | k = k/2;
|
|---|
| 143 | }
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | private void sink(int k) {
|
|---|
| 147 | while (2*k <= N) {
|
|---|
| 148 | int j = 2*k;
|
|---|
| 149 | if (j < N && greater(j, j+1)) j++;
|
|---|
| 150 | if (!greater(k, j)) break;
|
|---|
| 151 | exch(k, j);
|
|---|
| 152 | k = j;
|
|---|
| 153 | }
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 | /***********************************************************************
|
|---|
| 158 | * Iterators
|
|---|
| 159 | **********************************************************************/
|
|---|
| 160 |
|
|---|
| 161 | /**
|
|---|
| 162 | * Return an iterator that iterates over all of the elements on the
|
|---|
| 163 | * priority queue in ascending order.
|
|---|
| 164 | * <p>
|
|---|
| 165 | * The iterator doesn't implement <tt>remove()</tt> since it's optional.
|
|---|
| 166 | */
|
|---|
| 167 | @Override
|
|---|
| 168 | public Iterator<Integer> iterator() { return new HeapIterator(); }
|
|---|
| 169 |
|
|---|
| 170 | private class HeapIterator implements Iterator<Integer> {
|
|---|
| 171 | // create a new pq
|
|---|
| 172 | private IndexMinPQ<Key> copy;
|
|---|
| 173 |
|
|---|
| 174 | // add all elements to copy of heap
|
|---|
| 175 | // takes linear time since already in heap order so no keys move
|
|---|
| 176 | public HeapIterator() {
|
|---|
| 177 | copy = new IndexMinPQ<>(pq.length - 1);
|
|---|
| 178 | for (int i = 1; i <= N; i++)
|
|---|
| 179 | copy.insert(pq[i], keys[pq[i]]);
|
|---|
| 180 | }
|
|---|
| 181 |
|
|---|
| 182 | @Override
|
|---|
| 183 | public boolean hasNext() { return !copy.isEmpty(); }
|
|---|
| 184 | @Override
|
|---|
| 185 | public void remove() { throw new UnsupportedOperationException(); }
|
|---|
| 186 |
|
|---|
| 187 | @Override
|
|---|
| 188 | public Integer next() {
|
|---|
| 189 | if (!hasNext()) throw new NoSuchElementException();
|
|---|
| 190 | return copy.delMin();
|
|---|
| 191 | }
|
|---|
| 192 | }
|
|---|
| 193 | }
|
|---|