对于优先队列(堆),定义为每个父结点都要大于两个叶子结点。在优先队列中,元素的添加可以通过将每个元素添加到叶子中,再通过上浮算法swim来不断跟父结点比较,来维护优先队列的完整性。但是对于某些需要删除特定位置的时候,需要从头到尾遍历得到该元素的特定位置,再进行删除。
因此索引优先队列就是维护了一个逆序数组,保存了每个元素在优先队列的下标,如 我要删除 6这个元素 ,我能够通过qp[6]得到6在pq的位置下标,再通过将pq[qp[6]]和最后的一个结点进行交换,进行删除,然后下沉sink后,保持优先队列。
代码实现
package Mr_math;
public class IndexPQ {
private int N; //指针
private int []pq; //存放二叉堆的数组
private int []qp; //逆序 ,存放二叉堆的索引的下标,即pq[qp[i]] =qp[pq[i]] = i
private String []keys; //存放索引的元素
public IndexPQ(int maxSize) {
pq = new int[maxSize+1];
qp = new int[maxSize+1];
keys = new String[maxSize+1];
for(int i=0;i<=maxSize;i++) {
qp[i] = -1;
}
}
public boolean isEmpty() { //是否为空
return N == 0;
}
public boolean contain(int k) { //是否存在索引
return qp[k] == -1;
}
public static void exch(int[] a,int i,int j) { //交换两个数组索引的值
int k = a[i];
a[i] = a[j];
a[j] = k;
}
public void swim(int k) {
while(k>1&&pq[k/2]<pq[k]) {
exch(qp,pq[k/2],pq[k]);
exch(pq,k/2,k);
k = k/2;
}
}
public void sink(int k) {
while(k*2<=N) {
int j = k*2;
if(j<N&&pq[j]<pq[j+1]) j++;
if(pq[j]<pq[k]) break;
exch(qp,pq[j],pq[k]); //先维护qp或者pq都可以,因为,都是交换两个索引的值,无非是a与b交换或者b与a交换的区别罢了
exch(pq,j,k);
k = j;
}
}
public void insert(int k,String key) {
N++;
qp[k] = N;
pq[N] = k;
keys[k] = key;
swim(N);
}
public String min() {
return keys[qp[1]];
}
public int delIndexMin() {
int index = qp[1];
exch(qp,pq[1],pq[N--]);
exch(pq,1,N+1);
sink(1);
keys[pq[N+1]] = null;
pq[pq[N+1]] = -1;
return index;
}
public void delete(int k) {
int index = qp[k];
exch(qp,pq[index],pq[N--]);
exch(pq,index,N+1);
swim(index);
sink(index);
keys[k] = null;
qp[k] = -1;
}
public void Intetor() {
System.out.println("qp"+" " +"pq"+" "+"keys");
for(int i=1;i<=N;i++) {
System.out.println(qp[pq[i]]+" " +pq[i]+" "+keys[pq[i]]);
}
}
public static void main(String [] args) {
IndexPQ p = new IndexPQ(10);
p.insert(1, "1");
p.insert(2, "2");
p.insert(3, "3");
p.insert(6, "6");
p.Intetor();
p.delete(6);
p.Intetor();
}
}
在下沉或者上浮的时候,不仅仅要对pq数组进行维护,还要对qp维护,保持qp始终存着pq的索引的下标
如 sink中
public void sink(int k) {
while(k*2<=N) {
int j = k*2;
if(j<N&&pq[j]<pq[j+1]) j++;
if(pq[j]<pq[k]) break;
exch(qp,pq[j],pq[k]); //先维护qp或者pq都可以,因为,都是交换两个索引的值,无非是a与b交换或者b与a交换的区别罢了
exch(pq,j,k);
k = j;
}
}
交换pq数组的两个元素的位置的同时也要交换qp数组相对应的位置,而且先交换pq和qp并没有关系。
运行结果
`