简体   繁体   English

Dijkstra的最短路径

[英]Shortest Path with Dijkstra

I using this exact code for this. 使用这个确切的代码 I modified it a little. 我修改了一下。 So far I added a start and end node index to the calculateShortestDistances() method. 到目前为止,我在calculateShortestDistances()方法中添加了一个开始和结束节点索引。 Also the path ArrayList for collecting the path node indexes. 路径ArrayList也用于收集路径节点索引。 Also: new to Java... 另外:Java新手......

How do I collect the indexes of nodes in the path ArrayList? 如何收集path ArrayList中的节点索引?

I just can't come up with the solution on a level that I am not even positive this code could do what I want. 我只是无法提出解决方案,我甚至不肯定这个代码可以做我想要的。 I only have intuition on my side and little time. 我只有直觉和很少的时间。

What I tried: 我尝试了什么:

  • Adding the nextNode value to the list then removing it if it was not a shorter distance. 将nextNode值添加到列表中,如果距离不短,则将其删除。
  • Adding the neighbourIndex to the list then removing it if it was not a shorter distance. 将neighbourIndex添加到列表中,如果距离不短,则将其删除。
  • I made a Path.java with ArrayList but that was went nowhere (it was a class with a public variable named path) but it went nowhere. 我使用ArrayList创建了一个Path.java但是它无处可去(它是一个带有名为path的公共变量的类),但它无处可去。

Main.java: Main.java:

public class Main {
  public static void main(String[] args) {
    Edge[] edges = {
      new Edge(0, 2, 1), new Edge(0, 3, 4), new Edge(0, 4, 2),
      new Edge(0, 1, 3), new Edge(1, 3, 2), new Edge(1, 4, 3),
      new Edge(1, 5, 1), new Edge(2, 4, 1), new Edge(3, 5, 4),
      new Edge(4, 5, 2), new Edge(4, 6, 7), new Edge(4, 7, 2),
      new Edge(5, 6, 4), new Edge(6, 7, 5)
    };
    Graph g = new Graph(edges);
    g.calculateShortestDistances(4,6);
    g.printResult(); // let's try it !

    System.out.println(g.path);
  }
}

Graph.java: Graph.java:

This is the Graph.java file. 这是Graph.java文件。 Here I added a sAt and eAt variable, so I can tell it what path I am after. 在这里我添加了一个sAteAt变量,所以我可以告诉它我追求的是什么路径。 Also I created a public path ArrayList, where I intend to collect the path. 我还创建了一个公共path ArrayList,我打算收集路径。

import java.util.ArrayList;
// now we must create graph object and implement dijkstra algorithm
public class Graph {
  private Node[] nodes;
  private int noOfNodes;
  private Edge[] edges;
  private int noOfEdges;

  private int sAt;
  private int eAt;

  public ArrayList<Integer> path = new ArrayList<>();

  public Graph(Edge[] edges) {
    this.edges = edges;
    // create all nodes ready to be updated with the edges
    this.noOfNodes = calculateNoOfNodes(edges);
    this.nodes = new Node[this.noOfNodes];
    for (int n = 0; n < this.noOfNodes; n++) {
      this.nodes[n] = new Node();
    }
    // add all the edges to the nodes, each edge added to two nodes (to and from)
    this.noOfEdges = edges.length;
    for (int edgeToAdd = 0; edgeToAdd < this.noOfEdges; edgeToAdd++) {
      this.nodes[edges[edgeToAdd].getFromNodeIndex()].getEdges().add(edges[edgeToAdd]);
      this.nodes[edges[edgeToAdd].getToNodeIndex()].getEdges().add(edges[edgeToAdd]);
    }
  }
  private int calculateNoOfNodes(Edge[] edges) {
    int noOfNodes = 0;
    for (Edge e : edges) {
      if (e.getToNodeIndex() > noOfNodes)
        noOfNodes = e.getToNodeIndex();
      if (e.getFromNodeIndex() > noOfNodes)
        noOfNodes = e.getFromNodeIndex();
    }
    noOfNodes++;
    return noOfNodes;
  }

  public void calculateShortestDistances(int startAt, int endAt) {

    // node 0 as source
    this.sAt = startAt;
    this.eAt = endAt;
    this.nodes[startAt].setDistanceFromSource(0);
    int nextNode = startAt;
    // visit every node
    for (int i = 0; i < this.nodes.length; i++) {
      // loop around the edges of current node
      ArrayList<Edge> currentNodeEdges = this.nodes[nextNode].getEdges();

      for (int joinedEdge = 0; joinedEdge < currentNodeEdges.size(); joinedEdge++) {

        int neighbourIndex = currentNodeEdges.get(joinedEdge).getNeighbourIndex(nextNode);
        // only if not visited

        if (!this.nodes[neighbourIndex].isVisited()) {
          int tentative = this.nodes[nextNode].getDistanceFromSource() + currentNodeEdges.get(joinedEdge).getLength();

          if (tentative < nodes[neighbourIndex].getDistanceFromSource()) {
            nodes[neighbourIndex].setDistanceFromSource(tentative);



          }
        }

      }
      // all neighbours checked so node visited
      nodes[nextNode].setVisited(true);
      // next node must be with shortest distance
      nextNode = getNodeShortestDistanced();
   }
  }
  // now we're going to implement this method in next part !
  private int getNodeShortestDistanced() {
    int storedNodeIndex = 0;
    int storedDist = Integer.MAX_VALUE;
    for (int i = 0; i < this.nodes.length; i++) {
      int currentDist = this.nodes[i].getDistanceFromSource();

      if (!this.nodes[i].isVisited() && currentDist < storedDist) {
        storedDist = currentDist;
        storedNodeIndex = i;

      } 
    }
    return storedNodeIndex;
  }
  // display result
  public void printResult() {
    String output = "Number of nodes = " + this.noOfNodes;
    output += "\nNumber of edges = " + this.noOfEdges;

    output += "\nDistance from "+sAt+" to "+eAt+":" + nodes[eAt].getDistanceFromSource();

    System.out.println(output);
  }
  public Node[] getNodes() {
    return nodes;
  }
  public int getNoOfNodes() {
    return noOfNodes;
  }
  public Edge[] getEdges() {
    return edges;
  }
  public int getNoOfEdges() {
    return noOfEdges;
  }
}

Addittionally here are the Edge.java and the Node.java classes. 另外这里是Edge.java和Node.java类。

Node.java: Node.java:

import java.util.ArrayList;
public class Node {
  private int distanceFromSource = Integer.MAX_VALUE;
  private boolean visited;
  private ArrayList<Edge> edges = new ArrayList<Edge>(); // now we must create edges
  public int getDistanceFromSource() {
    return distanceFromSource;
  }
  public void setDistanceFromSource(int distanceFromSource) {
    this.distanceFromSource = distanceFromSource;
  }
  public boolean isVisited() {
    return visited;
  }
  public void setVisited(boolean visited) {
    this.visited = visited;
  }
  public ArrayList<Edge> getEdges() {
    return edges;
  }
  public void setEdges(ArrayList<Edge> edges) {
    this.edges = edges;
  }
}

Edge.java Edge.java

public class Edge {
  private int fromNodeIndex;
  private int toNodeIndex;
  private int length;
  public Edge(int fromNodeIndex, int toNodeIndex, int length) {
    this.fromNodeIndex = fromNodeIndex;
    this.toNodeIndex = toNodeIndex;
    this.length = length;
  }
  public int getFromNodeIndex() {
    return fromNodeIndex;
  }
  public int getToNodeIndex() {
    return toNodeIndex;
  }
  public int getLength() {
    return length;
  }
  // determines the neighbouring node of a supplied node, based on the two nodes connected by this edge
  public int getNeighbourIndex(int nodeIndex) {
    if (this.fromNodeIndex == nodeIndex) {
      return this.toNodeIndex;
    } else {
      return this.fromNodeIndex;
   }
  }
}

I know it looks like a homework. 我知道这看起来像是一个家庭作业。 Trust me it isn't. 相信我不是。 On the other hand I have not much time to finish it, that is why I do it at Sunday. 另一方面,我没有太多时间完成它,这就是为什么我在周日这样做。 Also I am aware how Dijkstra algorithm works, I understand the concept, I can do it on paper. 另外我知道Dijkstra算法是如何工作的,我理解这个概念,我可以在纸上做到。 But collecting the path is beyond me. 但收集路径超出了我的范围。

Thanks for Christian H. Kuhn 's and second 's comments I managed to come up with the code. 感谢Christian H. Kuhn第二次评论,我设法提出了代码。

I modified it as follows (I only put in the relevant parts) 我把它修改如下(我只放入相关部分)

Node.java Here I added a setPredecessor(Integer predecessor) and a getPredecessor() methods to set and get the value of the private variable predecessor (so I follow the original code's style too). Node.java这里我添加了一个setPredecessor(Integer predecessor)和一个getPredecessor()方法来设置和获取私有变量的predecessor的值(所以我也遵循原始代码的样式)。

  [...]
  private int predecessor;

  [...]
  public int getPredecessor(){
    return predecessor;
  }
  public void setPredecessor(int predecessor){
    this.predecessor = predecessor;
  }
  [...]

Graph.java Here I created the calculatePath() and getPath() methods. Graph.java这里我创建了calculatePath()getPath()方法。 calculatePath() does what the commenters told me to do. calculatePath()执行评论者告诉我的操作。 The getPath() returns the ArrayLists for others to use. getPath()返回ArrayLists以供其他人使用。

  [...]

  private int sAt;
  private int eAt;

  private ArrayList<Integer> path = new ArrayList<Integer>();

  [...]

  public void calculateShortestDistances(int startAt, int endAt) {

  [...]
          if (tentative < nodes[neighbourIndex].getDistanceFromSource()) {
            nodes[neighbourIndex].setDistanceFromSource(tentative);
            nodes[neighbourIndex].setPredecessor(nextNode);
          }

  [...]
  public void calculatePath(){
        int nodeNow = eAt;

        while(nodeNow != sAt){
            path.add(nodes[nodeNow].getPredecessor());
            nodeNow = nodes[nodeNow].getPredecessor();

        }

    }

    public ArrayList<Integer> getPath(){

        return path;

    }
    [...]

Main.java so here I can do this now: Main.java所以我现在可以这样做:

[...]
Graph g = new Graph(edges);
g.calculateShortestDistances(5,8);
g.calculatePath();

String results =  "";

ArrayList<Integer> path = g.getPath();

System.out.println(path);
[...]

I know it shows the path backwards, but that is not a problem, as I can always reverse it. 我知道它显示了向后的路径,但这不是问题,因为我总是可以逆转它。 The point is: I not only have the the distance from node to node, but the path through nodes too. 关键是:我不仅具有从节点到节点的距离,而且还有通过节点的路径。 Thank you for the help. 感谢您的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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