简体   繁体   中英

Prim Algorithm Priority Queue

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:

  1. The default implementation of PriorityQueue cannot re-order items within the queue dynamically. In other words, when you change the key after adding items in, it won't cause the items already in the queue to change their ordering.
  2. When you first add nodes into the PriorityQueue, they are all of the same priority. Therefore, according to the API for PriorityQueue,

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.

  1. If you want an efficient implementation of Prim's, you should not use PriorityQueue's contains() method to check inside the queue as this is an O(N) operation. Instead, use a boolean array to keep track of which items are in the queue or not which is O(1) lookup.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM