▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列
● 优先队列
1 package package01; 2 3 import java.util.Comparator; 4 import java.util.Iterator; 5 import java.util.NoSuchElementException; 6 import edu.princeton.cs.algs4.StdIn; 7 import edu.princeton.cs.algs4.StdOut; 8 9 public class class01<Key> implements Iterable<Key> 10 { 11 private int n; // 实际元素数 12 private Key[] pq; // 放堆的数组,注意 pq[0] 不使用 13 private Comparator<Key> comparator; // 比较器 14 15 public class01(int initCapacity) 16 { 17 n = 0; 18 pq = (Key[]) new Object[initCapacity + 1]; 19 } 20 21 public class01(int initCapacity, Comparator<Key> comparator) 22 { 23 n = 0; 24 pq = (Key[]) new Object[initCapacity + 1]; 25 comparator = comparator; 26 } 27 28 public class01() 29 { 30 this(1); // 对象自身的指针可以当构造函数名用 31 } 32 33 public class01(Comparator<Key> comparator) 34 { 35 this(1, comparator); 36 } 37 38 public class01(Key[] keys) // 含传入数组的构造函数 39 { 40 n = keys.length; 41 pq = (Key[]) new Object[keys.length + 1]; 42 for (int i = 0; i < n; i++) 43 pq[i + 1] = keys[i]; 44 for (int k = n / 2; k >= 1; k--)// 逐元素下沉建堆 45 sink(k); 46 } 47 48 public boolean isEmpty() 49 { 50 return n == 0; 51 } 52 53 public int size() 54 { 55 return n; 56 } 57 58 public Key max() // 取最大元素(堆顶) 59 { 60 if (isEmpty()) 61 throw new NoSuchElementException("Priority queue underflow"); 62 return pq[1]; 63 } 64 65 public Key delMax() // 弹出最大元素 66 { 67 if (isEmpty()) 68 throw new NoSuchElementException("Priority queue underflow"); 69 Key max = pq[1]; 70 exch(1, n--); // 把最后的元素放到堆顶,然后下沉 71 sink(1); 72 pq[n + 1] = null; // 帮助垃圾回收 73 if ((n > 0) && (n == (pq.length - 1) / 4)) // 减少堆尺寸 74 resize(pq.length / 2); 75 return max; 76 } 77 78 private void resize(int capacity) // 调整堆大小 79 { 80 assert capacity > n; 81 Key[] temp = (Key[]) new Object[capacity]; // 建一个新堆,然后搬进去 82 for (int i = 1; i <= n; i++) 83 temp[i] = pq[i]; 84 pq = temp; 85 } 86 87 public void insert(Key x) // 插入新元素 88 { 89 if (n == pq.length - 1) // 堆满了,扩建 90 resize(2 * pq.length); 91 92 pq[++n] = x; // 把新元素放到堆最后,然后上浮 93 swim(n); 94 } 95 96 private void swim(int k) // 上浮 97 { 98 for (; k > 1 && less(k / 2, k); k = k / 2) 99 exch(k, k / 2); 100 } 101 102 private void sink(int k) // 下沉 103 { 104 for (int j = k + k; j <= n; exch(k, j), k = j, j = k + k) 105 { 106 if (j < n && less(j, j + 1)) // 选择 a[k] 子节点中较大者 107 j++; 108 if (!less(k, j)) // 调整 a[k] 及其子节点,若 a[k] > a[j] 则停止调整 109 break; 110 } 111 } 112 113 private boolean less(int i, int j) // 需要小根堆时把两个不等号变向,其他所有地方都不改 114 { 115 if (comparator == null) 116 return ((Comparable<Key>) pq[i]).compareTo(pq[j]) < 0; 117 //return ((Comparable<Key>) pq[i]).compareTo(pq[j]) > 0; 118 else 119 return comparator.compare(pq[i], pq[j]) < 0; 120 //return comparator.compare(pq[i], pq[j]) > 0; 121 } 122 123 private void exch(int i, int j) 124 { 125 Key swap = pq[i]; 126 pq[i] = pq[j]; 127 pq[j] = swap; 128 } 129 130 private boolean isMaxHeap() 131 { 132 return isMaxHeap(1); 133 } 134 135 private boolean isMaxHeap(int k) 136 { 137 if (k > n) 138 return true; 139 int left = 2 * k, right = 2 * k + 1; 140 if (left <= n && less(k, left) || right <= n && less(k, right)) 141 return false; 142 return isMaxHeap(left) && isMaxHeap(right); 143 } 144 145 public Iterator<Key> iterator() // 迭代器 146 { 147 return new HeapIterator(); 148 } 149 150 private class HeapIterator implements Iterator<Key> 151 { 152 private class01<Key> copy; 153 154 public HeapIterator() 155 { 156 if (comparator == null) 157 copy = new class01<Key>(size()); 158 else 159 copy = new class01<Key>(size(), comparator); 160 for (int i = 1; i <= n; i++) 161 copy.insert(pq[i]); 162 } 163 164 public boolean hasNext() 165 { 166 return !copy.isEmpty(); 167 } 168 169 public void remove() 170 { 171 throw new UnsupportedOperationException(); 172 } 173 174 public Key next() 175 { 176 if (!hasNext()) 177 throw new NoSuchElementException(); 178 return copy.delMax(); 179 } 180 } 181 182 public static void main(String[] args) // 交互式出入优先队列 183 { 184 class01<String> pq = new class01<String>(); 185 for(; !StdIn.isEmpty();) 186 { 187 String item = StdIn.readString(); 188 if (!item.equals("-")) 189 pq.insert(item); 190 else if (!pq.isEmpty()) 191 StdOut.print(pq.delMax() + " "); 192 } 193 StdOut.println("(" + pq.size() + " left on pq)"); 194 } 195 }
● 索引优先队列
1 package package01; 2 3 import java.util.Iterator; 4 import java.util.NoSuchElementException; 5 import edu.princeton.cs.algs4.StdRandom; 6 import edu.princeton.cs.algs4.StdOut; 7 8 public class class01<Key extends Comparable<Key>> implements Iterable<Integer> 9 { 10 private int maxN; // 队列最大元素个数 11 private int n; 12 private int[] pq; // 索引堆,初值为 0,pq[0] 不用,pq[i] == j 表示堆的数组表示中第 i 位置上的元素是 keys[j] 13 private int[] qp; // 索引堆的逆,初值为 -1,qp[pq[i]] = pq[qp[i]] = i,qp[j] == i 表示元素 keys[i] 在堆的数组表示中位于第 i 的位置 14 private Key[] keys; // 仅保存值(不移动) 15 16 public class01(int inputMaxN) 17 { 18 if (maxN < 0) 19 throw new IllegalArgumentException(" <construct> maxN < 0. "); 20 maxN = inputMaxN; 21 n = 0; 22 pq = new int[maxN + 1]; 23 qp = new int[maxN + 1]; 24 keys = (Key[]) new Comparable[maxN + 1]; 25 for (int i = 0; i <= maxN; i++) 26 qp[i] = -1; 27 } 28 29 public boolean isEmpty() 30 { 31 return n == 0; 32 } 33 34 public boolean contains(int i) // 判断 qp 中第 i 位置是否被占用 35 { 36 if (i < 0 || i >= maxN) 37 throw new IllegalArgumentException(); 38 return qp[i] != -1; 39 } 40 41 public int size() 42 { 43 return n; 44 } 45 46 public void insert(int i, Key key) 47 { 48 if (i < 0 || i >= maxN) 49 throw new IllegalArgumentException(); 50 if (contains(i)) 51 throw new IllegalArgumentException(" <insert> exist i already exist. "); 52 n++; // 新元素插到末尾,然后上浮 53 qp[i] = n; 54 pq[n] = i; 55 keys[i] = key; 56 swim(n); 57 } 58 59 public int topIndex() 60 { 61 if (n == 0) 62 throw new NoSuchElementException(" <maxIndex> underflow. "); 63 return pq[1]; 64 } 65 66 public Key topKey() // 显示堆顶元素 67 { 68 if (n == 0) 69 throw new NoSuchElementException(" <maxKey> underflow. "); 70 return keys[pq[1]]; 71 } 72 73 public int delTop() // 弹出堆顶元素 74 { 75 if (n == 0) 76 throw new NoSuchElementException(" <delMax> underflow. "); 77 int top = pq[1]; 78 exch(1, n--); // 将堆尾元素换到堆顶,然后下沉 79 sink(1); 80 //assert pq[n + 1] == top; // 确保原来堆顶的元素被替换到了最后 81 qp[top] = -1; // 清除尾部元素的占用(代表被弹出的堆顶元素) 82 keys[top] = null; // 有助于垃圾回收 83 pq[n + 1] = -1; // 可以不要? 84 return top; 85 } 86 87 public Key keyOf(int i) // 查询 keys 中第 i 个元素 88 { 89 if (i < 0 || i >= maxN) 90 throw new IllegalArgumentException(); 91 if (!contains(i)) 92 throw new NoSuchElementException(" <KeyOf> index i not exist. "); 93 else return keys[i]; 94 } 95 96 public void changeKey(int i, Key key) // 在keys 的第 i 位置上替换成元素 key,然后调整其在堆中的位置 97 { 98 if (i < 0 || i >= maxN) 99 throw new IllegalArgumentException(); 100 if (!contains(i)) 101 throw new NoSuchElementException(" <changeKey> index i not exist. "); 102 keys[i] = key; 103 swim(qp[i]); 104 sink(qp[i]); 105 } 106 107 public void increaseKey(int i, Key key) // 增加某个元素的键 108 { 109 if (i < 0 || i >= maxN) 110 throw new IllegalArgumentException(); 111 if (!contains(i)) 112 throw new NoSuchElementException(" <increaseKey> index i not exist. "); 113 if (keys[i].compareTo(key) >= 0) 114 throw new IllegalArgumentException(" <increaseKey> given key less than the older one. "); 115 keys[i] = key; // 替换后只要上浮即可 116 swim(qp[i]); 117 //sink(qp[i]); // 最小有优先队列中这里要改成下沉 118 } 119 120 public void decreaseKey(int i, Key key) // 减少某个元素的键 121 { 122 if (i < 0 || i >= maxN) 123 throw new IllegalArgumentException(); 124 if (!contains(i)) 125 throw new NoSuchElementException(" <decreaseKey> index is not in the priority queue. "); 126 if (keys[i].compareTo(key) <= 0) 127 throw new IllegalArgumentException(" <decreaseKey> given key mroe than the older one. "); 128 keys[i] = key; // 替换后只要下沉即可 129 sink(qp[i]); 130 //swim(qp[i]); // 最小有优先队列中这里要改成上浮 131 } 132 133 public void delete(int i) // 删除节点 134 { 135 if (i < 0 || i >= maxN) 136 throw new IllegalArgumentException(); 137 if (!contains(i)) 138 throw new NoSuchElementException(" <delete> index i not exist. "); 139 int index = qp[i]; // 把目标元素与堆尾元素互换,然后调整 140 exch(index, n--); 141 swim(index); 142 sink(index); 143 keys[i] = null; 144 qp[i] = -1; 145 } 146 147 private boolean less(int i, int j) // 最大优先队列用 less 来做上浮和下沉 148 { 149 return keys[pq[i]].compareTo(keys[pq[j]]) < 0; 150 } 151 152 private boolean greater(int i, int j) // 最小优先队列用 greater 来做上浮和下沉 153 { 154 return keys[pq[i]].compareTo(keys[pq[j]]) > 0; 155 } 156 157 private void exch(int i, int j) // 单纯交换 i 和 j(不用调整位置?) 158 { 159 int swap = pq[i]; 160 pq[i] = pq[j]; 161 pq[j] = swap; 162 qp[pq[i]] = i; 163 qp[pq[j]] = j; 164 } 165 166 private void swim(int k) 167 { 168 for (; k > 1 && less(k >> 1, k); k >>= 1) 169 //for (; k > 1 && greater(k >> 1, k); k >>= 1) // 最小优先队列用 170 exch(k, k >> 1); 171 } 172 173 private void sink(int k) 174 { 175 for (int j = k << 1; j <= n; exch(k, j), k = j, j = k << 1) 176 { 177 if (j < n && less(j, j + 1)) 178 //if (j < n && greater(j, j + 1)) // 最小优先队列用 179 j++; 180 if (!less(k, j)) 181 break; 182 } 183 } 184 185 public Iterator<Integer> iterator() // 迭代器,原理是临时建立一个把 key 排好序的堆用于迭代 186 { 187 return new HeapIterator(); 188 } 189 190 private class HeapIterator implements Iterator<Integer> 191 { 192 private class01<Key> copy; 193 194 public HeapIterator() 195 { 196 copy = new class01<Key>(pq.length - 1); 197 for (int i = 1; i <= n; i++) 198 copy.insert(pq[i], keys[pq[i]]); 199 } 200 201 public boolean hasNext() 202 { 203 return !copy.isEmpty(); 204 } 205 206 public void remove() 207 { 208 throw new UnsupportedOperationException(); 209 } 210 211 public Integer next() 212 { 213 if (!hasNext()) 214 throw new NoSuchElementException(); 215 return copy.delTop(); 216 } 217 } 218 219 public static void main(String[] args) 220 { 221 String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" }; 222 223 class01<String> pq = new class01<String>(strings.length); 224 for (int i = 0; i < strings.length; i++) // 入队 225 pq.insert(i, strings[i]); 226 227 for (int i : pq) // 用迭代器显示队列状态,等效于逐个出队 228 StdOut.println(i + " " + strings[i]); 229 StdOut.println(); 230 231 for (int i = 0; i < strings.length; i++) // 尝试改变元素的键 232 { 233 if (StdRandom.uniform() < 0.5) 234 pq.increaseKey(i, "zzz"); // 换成优先级更高的字符串 235 else 236 pq.decreaseKey(i, strings[i].substring(0, 1)); // 换成原来字符串的子串 237 } 238 239 for (; !pq.isEmpty();) // 诸葛弹出元素 240 { 241 String key = pq.maxKey(); 242 int i = pq.delMax(); 243 StdOut.println(i + " " + key); 244 } 245 StdOut.println(); 246 247 for (int i = 0; i < strings.length; i++) // 再次入队 248 pq.insert(i, strings[i]); 249 250 int[] perm = new int[strings.length]; // 随机删除,生成一个随机数组,按数组元素的值删减队列中的元素 251 for (int i = 0; i < strings.length; i++) 252 perm[i] = i; 253 StdRandom.shuffle(perm); 254 for (int i = 0; i < perm.length; i++) 255 { 256 String key = pq.keyOf(perm[i]); 257 pq.delete(perm[i]); 258 StdOut.println(perm[i] + " " + key); 259 } 260 } 261 }