Prim算法优先级队列

时间:2015-04-28 16:02:54

标签: java priority-queue prims-algorithm

我试图用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 个答案:

答案 0 :(得分:3)

一些事情:

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

    如果多个元素被绑定为最小值,则头部是其中一个元素 - 关系被任意破坏。

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

    1. 如果你想要有效地实现Prim,你不应该使用PriorityQueue的contains()方法来检查队列内部,因为这是一个O(N)操作。相反,使用布尔数组来跟踪队列中的哪些项目,哪些是O(1)查找。
    2. 对于重新排序队列的有效方法,请注意添加操作是有效的O(log(n)),而从队列前面的任何地方删除是O(n)应该是避免。所以,一个好的技巧是保持一个布尔值的visit []数组,如果Node i已被处理,则visit [i]为真。然后,您可以多次添加同一节点,因为知道将首先检索具有最低密钥的节点。如果在轮询队列中查找节点时,访问过的[node.id]已经为真,那么就跳过它。

      当然,为了使其工作,Node必须基于它包含的某个值而不是外部数组进行比较,这样您就可以在队列中拥有两个具有相同id但具有不同密钥的节点。 / p>