在很多应用中,允许用例引用进入优先队列中的元素是有必要的。做到这一点的一种简单方式是给每个元素一个索引。
另外,一种常见的情况是用例已经有了总量为N的多个元素,而且可能还同时使用了多个(平行)数组来存储这些元素的信息。此时,其他无关的用例代码可能已经在使用一个整数索引来引用这些无关元素了。这些考虑引导我们设计了如下所示的API。
public class IndexMinPQ> | 说明 | 比较次数的增长数量级 |
---|---|---|
IndexMinPQ(int maxN) | 创建一个最大容量为maxN的优先队列,索引的取值范围为0至maxN-1 | |
void insert(int i,Key key) | 插入一个元素,将它和索引k相关联 | logN |
void changeKey(int i,Key key) | 将索引为i的元素设为key | logN |
boolean contains(int i) | 是否存在索引为k的元素 | 1 |
void delete(int i) | 删除索引i及其相关联的元素 | logN |
Key minKey() | 返回最小元素 | 1 |
int minIndex() | 返回最小元素的索引 | 1 |
int delMin() | 删除最小元素并返回它的索引 | logN |
boolean isEmpty() | 优先队列是否为空 | 1 |
int size() | 优先队列的元素数量 | 1 |
理解这种数据结构的一个较好方法是将它看成一个能够快速访问其中最小元素的数组。事实上它还要更好——它能够快速访问数组的一个特定子集中的最小元素(指所有被插入的元素)。换句话说,可以将名为pq的IndexMinPQ类优先队列看做数组pq[0…N-1]中的一部分元素的代表。将pq.insert(i,key)看做将i加入这个子集并使pq[i] = key,pq.changeKey(i,key)则代表令pq[i]=key。这两种操作没有改变其他操作所依赖的数据结构,其中最重要的就是delMin()(删除最小元素并返回min的索引)和changeKey(i,key)(改变数据结构中没有索引对应的键值即pq[i]=key)。这些操作在许多应用中都有很重要并且依赖于对元素的引用(索引)。
一般来说,当堆发生变化时,我们可以用adjustDown(向下调整堆)或adjustUp(向上调整堆)来恢复堆的有序性。在这些操作中,我们可以用索引查找元素。能够定位堆中的任意元素也使我们在API中加入一个delete(int i)操作。
索引优先队列用例见索引优先队列用例(多路归并)
package xwq.dt;
import java.util.Iterator;
import java.util.NoSuchElementException;
import xwq.util.StdOut;
import xwq.util.StdRandom;
/**
* 使用二叉堆实现的索引最小优先队列
* class IndexMinPQ是一个支持泛型的索引优先队列。
* IndexMinPQ支持普通的insert、delete-the-minimum、delete以及change-the-key方法。
* 用户可以使用队列中的0到maxN-1号索引执行删除和修改方法。
* IndexMinPQ支持获取队列最小元素,队列最小元素索引操作。
* IndexMinPQ支持迭代器迭代所有插入的索引号。
*
* IndexMinPQ的实现使用二叉堆。
* The <em>insert</em>, <em>delete-the-minimum</em>, <em>delete</em>,
* <em>change-key</em>, <em>decrease-key</em>, and <em>increase-key</em>
* 操作时间复杂度为O(lgN).
* The <em>is-empty</em>, <em>size</em>, <em>min-index</em>, <em>min-key</em>, and <em>key-of</em>
* operations 时间复杂度为O(1).
* @author xwq
*
* @param <Key>
*/
public class IndexMinPQ <Key extends Comparable<Key>> implements Iterable<Integer> {
private int maxN; //索引优先队列中元素的最大个数
private int N; //当前索引优先队列中元素的个数
private int[] pq;//使用一级索引的二叉堆
private int[] qp;//pq的对称映射 qp[pq[i]] = pq[qp[i]] = i,用于映射key索引对应pq二叉堆中的位置
private Key[] keys; //keys[i] = priority of i
/**
* 初始化索引区间为(0到maxN-1)的空索引优先队列
* @param capacity