I am trying to implement Prim's algorithm in Java with a priority queue.
I can't find my mistake. :/ I just recognize that the queue doesn't order the nodes correctly.
example for a graph:
0 4 7 5
4 0 2 3
7 2 0 1
5 3 1 0
It always takes the node 4 as the second one. So it orders the queue like [node1, node4, node2, node3] and not [node1,node2, node3, node4]. What did I do wrong with the priority queue?
Greetings
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);
}
}
A few things:
If multiple elements are tied for least value, the head is one of those elements -- ties are broken arbitrarily.
So there is no guarantee of the initial order of the nodes.
For an efficient method of re-ordering the queue, note that an add operation is O(log(n)) which is efficient, while a remove from anywhere but the front of the queue is O(n) which should be avoided. So, a good trick would be to keep a boolean visited[] array, where visited[i] is true if Node i has already been processed. Then, you can add the same node multiple times, knowing that the one with the lowest key will be retrieved first. If when you poll the queue for a node, visited[node.id] is already true, then simply skip it.
Of course, in order for this to work, the Node must be comparable based on some value it contains rather than an external array, so that you can have two nodes with the same id in the queue but with different key.