gpt4 book ai didi

java - Prim 算法优先级队列

转载 作者:行者123 更新时间:2023-11-30 08:13:34 25 4
gpt4 key购买 nike

我正在尝试使用优先级队列在 Java 中实现 Prim 的算法。

我找不到我的错误。 :/我只是认识到队列没有正确排序节点。

图表示例:

0 4 7 5
4 0 2 3
7 2 0 1
5 3 1 0

它始终以节点 4 作为第二个。所以它将队列排序为 [node1, node4, node2, node3] 而不是 [node1,node2, node3, node4]。我对优先级队列做错了什么?

问候

    public class PrimAlgorithm {

private static int[] par; // parent
private static int[] key; // value
private static int sum;


public static void prim(Graph g){

Node[] nodes = g.getNodes();
key = new int[g.getMatrix().length];
par = new int[g.getMatrix().length];


PriorityQueue<Node> queue = new PriorityQueue<Node>(42, new Comparator<Node>(){
public int compare(Node v1, Node v2){
return Integer.valueOf(key[v1.getId()-1]).compareTo(Integer.valueOf(key[v2.getId()-1]));



for (Node n : nodes) {
int x = n.getId()-1;
key[x] = 1000;
par[x] = 0;
queue.add(n);
}

key[0] = 0;


while(!queue.isEmpty()) {
Node n = queue.poll();

List<Node> neighbours = n.getNeighbors();

for (Node m : neighbours){
if ( queue.contains(m) && g.getEdge(n, m).getWeight() !=0 && g.getEdge(n, m).getWeight() < key[m.getId()-1]){

par[m.getId()-1] = n.getId();
key[m.getId()-1] = g.getEdge(n, m).getWeight();

}
}
}

for (int i=0; i < key.length; i++){
sum += key[i];
}

System.out.println("Das Gewicht des minimalen Spannbaumes lautet: " + sum);
System.out.println("Der Spannbaum ergibt sich wie folgt: " );
//fängt ab 1 an sonst, hätten wir immer noch einen Nullknoten
for(int i=0; i <par.length; i++){
System.out.println("Der Vorgänger von Knoten: " + " "+ (i+1) + "-> " + par[i] + " Gewicht "
+ key[i]);
}

}

public static void main(String[] args) {
System.out.println("Prim Algorithmus zu Berechnung des minimalen Spannbaums.");
Graph g = new Graph();

prim(g);
}

}

最佳答案

一些事情:

  1. PriorityQueue 的默认实现无法对队列中的项目进行动态重新排序。换句话说,当您在添加项目后更改键时,不会导致队列中已经存在的项目改变它们的顺序。
  2. 当您第一次将节点添加到 PriorityQueue 时,它​​们都具有相同的优先级。因此,根据 PriorityQueue 的 API,

If multiple elements are tied for least value, the head is one of those elements -- ties are broken arbitrarily.

因此无法保证节点的初始顺序。

  1. 如果您想要高效地实现 Prim,则不应使用 PriorityQueue 的 contains() 方法来检查队列内部,因为这是一个 O(N) 操作。相反,使用 boolean 数组来跟踪哪些项目在队列中或不在队列中,这是 O(1) 查找。

对于重新排序队列的有效方法,请注意,添加操作是高效的 O(log(n)),而从除队列前端以外的任何地方删除操作是 O(n),这应该是避免了。因此,一个好的技巧是保留一个 boolean 型 visited[] 数组,如果节点 i 已被处理,则 visited[i] 为真。然后,您可以多次添加同一个节点,知道将首先检索具有最低键的节点。如果当您轮询队列中的节点时,visited[node.id] 已经为真,则只需跳过它。

当然,为了让它工作,节点必须基于它包含的某个值而不是外部数组进行比较,这样你就可以在队列中有两个具有相同 ID 但具有不同键的节点。

关于java - Prim 算法优先级队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29924373/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com