优先队列不工作
PriorityQueue not working
我正在尝试自己在 java 中实现 Dijkstra 算法。我有一个最小优先级队列,用于存储按当前最短路径排序的节点。
第一步很顺利,我将起始节点设置为距离0,其他设置为Integer.MAX_VALUE。起始节点已正确轮询。但是,在我删除第一个节点后,删除的第二个节点不是距离最小的节点。我不知道为什么。有意见吗?
这是我的代码
public void Dijkstra(Node s){
initialize(s);
List<Node> set = new ArrayList<Node>();
Comparator<Node> c = new CompareNode();
PriorityQueue<Node> Q = new PriorityQueue<Node>(V,c);
for (Node q: Nodes){
Q.add(q);
}
while (Q.size()!=0){
Node u = Q.remove();
System.out.println();
System.out.println(u + " is removed with dis " + u.getD());
set.add(u);
for (Node w: u.getWeightedAdj().keySet()){
relax(u,w);
}
}
}
public void initialize(Node s){
for (Node v: Nodes){
v.setD(Integer.MAX_VALUE);
v.setPredecessor(null);
}
s.setD(0);
}
public void relax(Node u, Node w){
if (w.getD()>u.getD()+u.getWeightedAdj().get(w)){
w.setD(u.getD()+u.getWeightedAdj().get(w));
w.setPredecessor(u);
}
}
和比较器class
import java.util.Comparator;
public class CompareNode implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
if (o1.getD()>o2.getD())
return 1;
if (o1.getD()<o2.getD())
return -1;
return 0;
}
}
当我运行它的时候,结果是这样的
A is removed with dis 0
E is removed with dis 2147483647
C is removed with dis 2
D is removed with dis -2147483648
B is removed with dis 3
问题是 PriorityQueue 在添加元素时假定元素的顺序不能更改。
在您的示例中,当将节点添加到队列(起始节点除外)时,您的所有距离都是 MaxInt,因此它们以有效的随机顺序放入队列。
然后您调整距离,但 PriorityQueue 不知道这些调整,因此继续 return 原始顺序中的元素。
对此的标准做法是在距离发生变化时在优先级队列中插入元素。 (当一个元素从队列中移除时,需要测试是否已经访问过这个元素,因为同一个元素可以在队列中出现多次。)
发现节点后将其添加到队列中会更容易。 IE。一开始只添加根节点,然后在每次迭代中添加新发现的尚未处理的节点。在迭代步骤中,您需要检查队列中是否有新节点,如果新距离更短,则可能会更新它们。
我正在尝试自己在 java 中实现 Dijkstra 算法。我有一个最小优先级队列,用于存储按当前最短路径排序的节点。
第一步很顺利,我将起始节点设置为距离0,其他设置为Integer.MAX_VALUE。起始节点已正确轮询。但是,在我删除第一个节点后,删除的第二个节点不是距离最小的节点。我不知道为什么。有意见吗?
这是我的代码
public void Dijkstra(Node s){
initialize(s);
List<Node> set = new ArrayList<Node>();
Comparator<Node> c = new CompareNode();
PriorityQueue<Node> Q = new PriorityQueue<Node>(V,c);
for (Node q: Nodes){
Q.add(q);
}
while (Q.size()!=0){
Node u = Q.remove();
System.out.println();
System.out.println(u + " is removed with dis " + u.getD());
set.add(u);
for (Node w: u.getWeightedAdj().keySet()){
relax(u,w);
}
}
}
public void initialize(Node s){
for (Node v: Nodes){
v.setD(Integer.MAX_VALUE);
v.setPredecessor(null);
}
s.setD(0);
}
public void relax(Node u, Node w){
if (w.getD()>u.getD()+u.getWeightedAdj().get(w)){
w.setD(u.getD()+u.getWeightedAdj().get(w));
w.setPredecessor(u);
}
}
和比较器class
import java.util.Comparator;
public class CompareNode implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
if (o1.getD()>o2.getD())
return 1;
if (o1.getD()<o2.getD())
return -1;
return 0;
}
}
当我运行它的时候,结果是这样的
A is removed with dis 0
E is removed with dis 2147483647
C is removed with dis 2
D is removed with dis -2147483648
B is removed with dis 3
问题是 PriorityQueue 在添加元素时假定元素的顺序不能更改。
在您的示例中,当将节点添加到队列(起始节点除外)时,您的所有距离都是 MaxInt,因此它们以有效的随机顺序放入队列。
然后您调整距离,但 PriorityQueue 不知道这些调整,因此继续 return 原始顺序中的元素。
对此的标准做法是在距离发生变化时在优先级队列中插入元素。 (当一个元素从队列中移除时,需要测试是否已经访问过这个元素,因为同一个元素可以在队列中出现多次。)
发现节点后将其添加到队列中会更容易。 IE。一开始只添加根节点,然后在每次迭代中添加新发现的尚未处理的节点。在迭代步骤中,您需要检查队列中是否有新节点,如果新距离更短,则可能会更新它们。