▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列
● 优先队列
package package01; import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01<Key> implements Iterable<Key>
{
private int n; // 实际元素数
private Key[] pq; // 放堆的数组,注意 pq[0] 不使用
private Comparator<Key> comparator; // 比较器 public class01(int initCapacity)
{
n = 0;
pq = (Key[]) new Object[initCapacity + 1];
} public class01(int initCapacity, Comparator<Key> comparator)
{
n = 0;
pq = (Key[]) new Object[initCapacity + 1];
comparator = comparator;
} public class01()
{
this(1); // 对象自身的指针可以当构造函数名用
} public class01(Comparator<Key> comparator)
{
this(1, comparator);
} public class01(Key[] keys) // 含传入数组的构造函数
{
n = keys.length;
pq = (Key[]) new Object[keys.length + 1];
for (int i = 0; i < n; i++)
pq[i + 1] = keys[i];
for (int k = n / 2; k >= 1; k--)// 逐元素下沉建堆
sink(k);
} public boolean isEmpty()
{
return n == 0;
} public int size()
{
return n;
} public Key max() // 取最大元素(堆顶)
{
if (isEmpty())
throw new NoSuchElementException("Priority queue underflow");
return pq[1];
} public Key delMax() // 弹出最大元素
{
if (isEmpty())
throw new NoSuchElementException("Priority queue underflow");
Key max = pq[1];
exch(1, n--); // 把最后的元素放到堆顶,然后下沉
sink(1);
pq[n + 1] = null; // 帮助垃圾回收
if ((n > 0) && (n == (pq.length - 1) / 4)) // 减少堆尺寸
resize(pq.length / 2);
return max;
} private void resize(int capacity) // 调整堆大小
{
assert capacity > n;
Key[] temp = (Key[]) new Object[capacity]; // 建一个新堆,然后搬进去
for (int i = 1; i <= n; i++)
temp[i] = pq[i];
pq = temp;
} public void insert(Key x) // 插入新元素
{
if (n == pq.length - 1) // 堆满了,扩建
resize(2 * pq.length); pq[++n] = x; // 把新元素放到堆最后,然后上浮
swim(n);
} private void swim(int k) // 上浮
{
for (; k > 1 && less(k / 2, k); k = k / 2)
exch(k, k / 2);
} private void sink(int k) // 下沉
{
for (int j = k + k; j <= n; exch(k, j), k = j, j = k + k)
{
if (j < n && less(j, j + 1)) // 选择 a[k] 子节点中较大者
j++;
if (!less(k, j)) // 调整 a[k] 及其子节点,若 a[k] > a[j] 则停止调整
break;
}
} private boolean less(int i, int j) // 需要小根堆时把两个不等号变向,其他所有地方都不改
{
if (comparator == null)
return ((Comparable<Key>) pq[i]).compareTo(pq[j]) < 0;
//return ((Comparable<Key>) pq[i]).compareTo(pq[j]) > 0;
else
return comparator.compare(pq[i], pq[j]) < 0;
//return comparator.compare(pq[i], pq[j]) > 0;
} private void exch(int i, int j)
{
Key swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
} private boolean isMaxHeap()
{
return isMaxHeap(1);
} private boolean isMaxHeap(int k)
{
if (k > n)
return true;
int left = 2 * k, right = 2 * k + 1;
if (left <= n && less(k, left) || right <= n && less(k, right))
return false;
return isMaxHeap(left) && isMaxHeap(right);
} public Iterator<Key> iterator() // 迭代器
{
return new HeapIterator();
} private class HeapIterator implements Iterator<Key>
{
private class01<Key> copy; public HeapIterator()
{
if (comparator == null)
copy = new class01<Key>(size());
else
copy = new class01<Key>(size(), comparator);
for (int i = 1; i <= n; i++)
copy.insert(pq[i]);
} public boolean hasNext()
{
return !copy.isEmpty();
} public void remove()
{
throw new UnsupportedOperationException();
} public Key next()
{
if (!hasNext())
throw new NoSuchElementException();
return copy.delMax();
}
} public static void main(String[] args) // 交互式出入优先队列
{
class01<String> pq = new class01<String>();
for(; !StdIn.isEmpty();)
{
String item = StdIn.readString();
if (!item.equals("-"))
pq.insert(item);
else if (!pq.isEmpty())
StdOut.print(pq.delMax() + " ");
}
StdOut.println("(" + pq.size() + " left on pq)");
}
}
● 索引优先队列
package package01; import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdOut; public class class01<Key extends Comparable<Key>> implements Iterable<Integer>
{
private int maxN; // 队列最大元素个数
private int n;
private int[] pq; // 索引堆,初值为 0,pq[0] 不用,pq[i] == j 表示堆的数组表示中第 i 位置上的元素是 keys[j]
private int[] qp; // 索引堆的逆,初值为 -1,qp[pq[i]] = pq[qp[i]] = i,qp[j] == i 表示元素 keys[i] 在堆的数组表示中位于第 i 的位置
private Key[] keys; // 仅保存值(不移动) public class01(int inputMaxN)
{
if (maxN < 0)
throw new IllegalArgumentException("\n<construct> maxN < 0.\n");
maxN = inputMaxN;
n = 0;
pq = new int[maxN + 1];
qp = new int[maxN + 1];
keys = (Key[]) new Comparable[maxN + 1];
for (int i = 0; i <= maxN; i++)
qp[i] = -1;
} public boolean isEmpty()
{
return n == 0;
} public boolean contains(int i) // 判断 qp 中第 i 位置是否被占用
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
return qp[i] != -1;
} public int size()
{
return n;
} public void insert(int i, Key key)
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (contains(i))
throw new IllegalArgumentException("\n<insert> exist i already exist.\n");
n++; // 新元素插到末尾,然后上浮
qp[i] = n;
pq[n] = i;
keys[i] = key;
swim(n);
} public int topIndex()
{
if (n == 0)
throw new NoSuchElementException("\n<maxIndex> underflow.\n");
return pq[1];
} public Key topKey() // 显示堆顶元素
{
if (n == 0)
throw new NoSuchElementException("\n<maxKey> underflow.\n");
return keys[pq[1]];
} public int delTop() // 弹出堆顶元素
{
if (n == 0)
throw new NoSuchElementException("\n<delMax> underflow.\n");
int top = pq[1];
exch(1, n--); // 将堆尾元素换到堆顶,然后下沉
sink(1);
//assert pq[n + 1] == top; // 确保原来堆顶的元素被替换到了最后
qp[top] = -1; // 清除尾部元素的占用(代表被弹出的堆顶元素)
keys[top] = null; // 有助于垃圾回收
pq[n + 1] = -1; // 可以不要?
return top;
} public Key keyOf(int i) // 查询 keys 中第 i 个元素
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<KeyOf> index i not exist.\n");
else return keys[i];
} public void changeKey(int i, Key key) // 在keys 的第 i 位置上替换成元素 key,然后调整其在堆中的位置
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<changeKey> index i not exist.\n");
keys[i] = key;
swim(qp[i]);
sink(qp[i]);
} public void increaseKey(int i, Key key) // 增加某个元素的键
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<increaseKey> index i not exist.\n");
if (keys[i].compareTo(key) >= 0)
throw new IllegalArgumentException("\n<increaseKey> given key less than the older one.\n");
keys[i] = key; // 替换后只要上浮即可
swim(qp[i]);
//sink(qp[i]); // 最小有优先队列中这里要改成下沉
} public void decreaseKey(int i, Key key) // 减少某个元素的键
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<decreaseKey> index is not in the priority queue.\n");
if (keys[i].compareTo(key) <= 0)
throw new IllegalArgumentException("\n<decreaseKey> given key mroe than the older one.\n");
keys[i] = key; // 替换后只要下沉即可
sink(qp[i]);
//swim(qp[i]); // 最小有优先队列中这里要改成上浮
} public void delete(int i) // 删除节点
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<delete> index i not exist.\n");
int index = qp[i]; // 把目标元素与堆尾元素互换,然后调整
exch(index, n--);
swim(index);
sink(index);
keys[i] = null;
qp[i] = -1;
} private boolean less(int i, int j) // 最大优先队列用 less 来做上浮和下沉
{
return keys[pq[i]].compareTo(keys[pq[j]]) < 0;
} private boolean greater(int i, int j) // 最小优先队列用 greater 来做上浮和下沉
{
return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
} private void exch(int i, int j) // 单纯交换 i 和 j(不用调整位置?)
{
int swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
qp[pq[i]] = i;
qp[pq[j]] = j;
} private void swim(int k)
{
for (; k > 1 && less(k >> 1, k); k >>= 1)
//for (; k > 1 && greater(k >> 1, k); k >>= 1) // 最小优先队列用
exch(k, k >> 1);
} private void sink(int k)
{
for (int j = k << 1; j <= n; exch(k, j), k = j, j = k << 1)
{
if (j < n && less(j, j + 1))
//if (j < n && greater(j, j + 1)) // 最小优先队列用
j++;
if (!less(k, j))
break;
}
} public Iterator<Integer> iterator() // 迭代器,原理是临时建立一个把 key 排好序的堆用于迭代
{
return new HeapIterator();
} private class HeapIterator implements Iterator<Integer>
{
private class01<Key> copy; public HeapIterator()
{
copy = new class01<Key>(pq.length - 1);
for (int i = 1; i <= n; i++)
copy.insert(pq[i], keys[pq[i]]);
} public boolean hasNext()
{
return !copy.isEmpty();
} public void remove()
{
throw new UnsupportedOperationException();
} public Integer next()
{
if (!hasNext())
throw new NoSuchElementException();
return copy.delTop();
}
} public static void main(String[] args)
{
String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" }; class01<String> pq = new class01<String>(strings.length);
for (int i = 0; i < strings.length; i++) // 入队
pq.insert(i, strings[i]); for (int i : pq) // 用迭代器显示队列状态,等效于逐个出队
StdOut.println(i + " " + strings[i]);
StdOut.println(); for (int i = 0; i < strings.length; i++) // 尝试改变元素的键
{
if (StdRandom.uniform() < 0.5)
pq.increaseKey(i, "zzz"); // 换成优先级更高的字符串
else
pq.decreaseKey(i, strings[i].substring(0, 1)); // 换成原来字符串的子串
} for (; !pq.isEmpty();) // 诸葛弹出元素
{
String key = pq.maxKey();
int i = pq.delMax();
StdOut.println(i + " " + key);
}
StdOut.println(); for (int i = 0; i < strings.length; i++) // 再次入队
pq.insert(i, strings[i]); int[] perm = new int[strings.length]; // 随机删除,生成一个随机数组,按数组元素的值删减队列中的元素
for (int i = 0; i < strings.length; i++)
perm[i] = i;
StdRandom.shuffle(perm);
for (int i = 0; i < perm.length; i++)
{
String key = pq.keyOf(perm[i]);
pq.delete(perm[i]);
StdOut.println(perm[i] + " " + key);
}
}
}