【问题标题】:How to implement Dijkstra's Algorithm to find the shortest path in Java如何实现 Dijkstra 算法以在 Java 中找到最短路径
【发布时间】:2015-04-29 15:36:30
【问题描述】:

我完全不知道该怎么做。我正在尝试对维基百科在 Dijkstra 上的带有优先级队列的伪代码进行编码,但我很难进行调整以适应我需要找到的内容。到目前为止,这是我的(不完整的)代码,非常感谢任何帮助。

public int doDijkstras (String startVertexName, String endVertexName, ArrayList< String > shortestPath) {
        PriorityQueue<QEntry> q = new PriorityQueue<QEntry>();
        int cost = 0;
        int newCost;
        QEntry pred = null;
        for (String s : this.getVertices()) {
            if (!s.equals(startVertexName)) {
                cost = Integer.MAX_VALUE;
                pred = null;
            }
            q.add(new QEntry(s, cost, pred, adjacencyMap.get(s)));
        }

        while (!q.isEmpty()) {
            QEntry curr = getMin(q);
            for (String s : curr.adj.keySet()) {
                newCost = curr.cost + this.getCost(curr.name, s);
                QEntry v = this.getVert(q, s);
                if (newCost < v.cost) {
                    v.cost = newCost;
                    v.pred = curr;
                    if (!q.contains(curr)) {
                        q.add(curr);
                    }
                }
            }
        }
    }

    private QEntry getMin(PriorityQueue<QEntry> q) {
        QEntry min = q.peek();
        for (QEntry temp : q) {
            if (min.cost > temp.cost) {
                min = temp;
            }
        }
        return min;
    }

    private QEntry getVert(PriorityQueue<QEntry> q, String s) {
        for (QEntry temp : q) {
            if (temp.name.equals(s)) {
                return temp;
            }
        }
        return null;
    }

    class QEntry {
        String name;
        int cost;
        QEntry pred;
        TreeMap<String, Integer> adj;

        public QEntry(String name, int cost, QEntry pred, TreeMap<String, Integer> adj) {
            this.name = name;
            this.cost = cost;
            this.adj = adj;
            this.pred = pred;
        }
    }

【问题讨论】:

  • 感谢您的编辑,第一篇文章试图弄清楚如何。
  • QEntry curr = getMin(q);--你为什么要对q做这种事?如果您覆盖QEntry#compareTo() 方法或使用自定义比较器创建q,您可以通过q.poll() 获得最小条目
  • 您有什么特别的问题?有什么你不知道如何翻译成 Java 的吗? (什么?)否则,有什么问题?
  • 我不知道如何从这一点开始。我该怎么做才能将最短路径添加到给定的 ArrayList 并返回最短路径的成本

标签: java dijkstra


【解决方案1】:

您忽略了算法的一个重要部分:何时停止。

维基百科上的伪代码是 Dijkstra 算法的变体,该算法计算从起始节点到与其相连的每个节点的最短路径。大伪代码块之后的注释解释了如何修改算法以仅找到特定目标的路径,然后是一个较短的块,解释如何提取路径。

不过,在英语中,当您处理优先级队列时,您需要注意目标元素是否被选中。当(如果有的话)它是,你知道没有比它的成本记录在目标队列条目中的路径更短的路径可以被发现,并由该条目及其前身链表示(以相反的顺序)。您通过遍历前任链来填充路径列表,并返回记录在目标队列条目中的值。

但是请注意,在您的代码中,如果起始顶点和目标顶点在图中未连接(包括目标根本不在图中),您最终将排空队列并退出while 循环的底部没有到达目标。您必须决定如何处理路径列表以及在这种情况下返回什么。

还要注意,您的代码似乎有几个错误,其中包括:

  • 如果起始顶点名称不是 this.getVertices() 迭代顺序中的第一个,则其队列条目将不会以成本 0 进行初始化,并且不太可能是从队列中选择的第一个元素。
  • 如果指定的起始顶点根本不在图中,那么您的代码将运行,并可能发出路径,但在这种情况下其输出是虚假的。
  • 您的队列元素(类型QEntry)没有自然顺序;要创建其元素具有此类类型的 PriorityQueue,您必须提供定义其相对优先级的 Comparator
  • 您将优先级队列用作普通列表。这本身不会使您的代码产生错误的结果,但它确实增加了其渐近复杂度。
  • 但是请注意,如果您使用标准的PriorityQueue作为优先级队列,那么您绝不能以可能改变其相对于任何其他入队对象的顺序的方式修改入队对象目的;相反,首先将其从队列中移除,修改它,然后再次入队。

【讨论】:

  • 非常感谢您的帮助(尤其是指出我的错误)。我为我糟糕的代码道歉。我的老师不太擅长教初学者(经常引用课堂上没有复习的材料,因此造成混乱),而我对编码还很陌生。
猜你喜欢
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-01
  • 1970-01-01
  • 2015-05-13
  • 1970-01-01
相关资源
最近更新 更多