我已经了解了优先级队列。但是当涉及索引优先级队列时,我对某些方法的实现有点困惑,例如 change(int k,Item item)和 delete(int i)。
更改(int k,项目项目)是将与k关联的项目更改为项目
delete(int i)是删除k及其关联项
public void changeKey(int i, Key key) {
if (i < 0 || i >= maxN) throw new IndexOutOfBoundsException();
if (!contains(i)) throw new NoSuchElementException("index is not in the priority queue");
keys[i] = key;
swim(qp[i]);
sink(qp[i]);
}
public void delete(int i) {
if (i < 0 || i >= maxN) throw new IndexOutOfBoundsException();
if (!contains(i)) throw new NoSuchElementException("index is not in the priority queue");
int index = qp[i];
exch(index, n--);
swim(index);
sink(index);
keys[i] = null;
qp[i] = -1;
}
private void swim(int k) {
while (k > 1 && greater(k/2, k)) {
exch(k, k/2);
k = k/2;
}
}
private void sink(int k) {
while (2*k <= n) {
int j = 2*k;
if (j < n && greater(j, j+1)) j++;
if (!greater(k, j)) break;
exch(k, j);
k = j;
}
}
private int maxN; // maximum number of elements on PQ
private int n; // number of elements on PQ
private int[] pq; // binary heap using 1-based indexing
private int[] qp; // inverse of pq - qp[pq[i]] = pq[qp[i]] = i
private Key[] keys; // keys[i] = priority of i
我理解接收器和游泳的操作。但是为什么在方法 delete(int i)和 changeKey(int我,密钥)有陈述swim(qp[i]/index);
和sink(qp[i]/index);
发生了什么?
我还想知道优先级队列和索引优先级队列之间的元素构造样式以及索引优先级队列中的二进制堆中存储的内容?索引还是元素?
答案 0 :(得分:6)
这些是在更改密钥时需要执行的二进制堆上的操作。每个节点&#39;优先级队列中保存在二进制堆中。当您添加项目时,该项目需要定位在正确的位置,因此二进制堆的规则是&#39;没破。
更改密钥也会发生同样的情况,您需要更改项目在优先级堆中的位置,这样规则就不会被破坏(该项目的子项不大于它,并且该项目的父项不是更小)。
这个优先级队列是用二进制堆实现的,这意味着它基于二叉树,这就是为什么你可以在这些方法中看到除以2的原因,因为它需要取项目/逐级下降并通过该划分实现(第一级有一个节点,第二级有两个节点,第三级有四个节点等,每个级别节点数乘以2)。
这篇文章只是对一个巨大而广泛的主题的介绍,我建议阅读更多关于它的内容(特别是&#39; heapify&#39;部分):check this out.
通常,重点是您只有一种方法可以更改密钥,它会同时调用swim
和sink
,因为上一个密钥可能更高或更低。它通常使用两种方法完成:decreaseKey
和increaseKey
,并且每种方法都只调用一个 - sink
或swim
。您的代码将这2种方法合并为1,这就是它调用sink
和swim
的原因。当新密钥高于旧密钥时,意味着它需要在堆中上升(swim
),当新密钥低于旧密钥时,它需要关闭(sink
)
BTW我的整个帖子假设我们正在使用最大堆 - 这意味着根节点具有最大值并且他的子节点具有更小的值等。还有一个最小堆,这是完全相反的。