java - Java 中的 Dijkstra 算法和源码变更

标签 java algorithm heap-memory shortest-path dijkstra

因此,我正在尝试实现 Dijkstra 算法,以找到两个城市之间的最短路径。 到目前为止我的类(class)是:

Edge.java

package com.company;

public class Edge {

        private int weight;
        private Vertex startVertex;
        private Vertex targetVertex;

        public Edge(int weight, Vertex startVertex, Vertex targetVertex) {
            this.weight = weight;
            this.startVertex = startVertex;
            this.targetVertex = targetVertex;
        }

        public double getWeight() {
            return weight;
        }

        public void setWeight(int weight) {
            this.weight = weight;
        }

        public Vertex getStartVertex() {
            return startVertex;
        }

        public void setStartVertex(Vertex startVertex) {
            this.startVertex = startVertex;
        }

        public Vertex getTargetVertex() {
            return targetVertex;
        }

        public void setTargetVertex(Vertex targetVertex) {
            this.targetVertex = targetVertex;
        }
    }

然后是 Vertex.java

package com.company;

import java.util.ArrayList;
import java.util.List;

public class Vertex implements Comparable<Vertex> {

    private String name;
    private List<Edge> adjacenciesList;
    private boolean visited;
    private Vertex predecessor;
    private double distance = Double.MAX_VALUE;

    public Vertex(String name) {
        this.name = name;
        this.adjacenciesList = new ArrayList<>();
    }

    public void addNeighbour(Edge edge) {
        this.adjacenciesList.add(edge);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Edge> getAdjacenciesList() {
        return adjacenciesList;
    }

    public void setAdjacenciesList(List<Edge> adjacenciesList) {
        this.adjacenciesList = adjacenciesList;
    }

    public boolean isVisited() {
        return visited;
    }

    public void setVisited(boolean visited) {
        this.visited = visited;
    }

    public Vertex getPredecessor() {
        return predecessor;
    }

    public void setPredecessor(Vertex predecessor) {
        this.predecessor = predecessor;
    }

    public double getDistance() {
        return distance;
    }

    public void setDistance(double distance) {
        this.distance = distance;
    }

    @Override
    public String toString() {
        return this.name;
    }

    @Override
    public int compareTo(Vertex otherVertex) {
        return Double.compare(this.distance, otherVertex.getDistance());
    }
}

和 DijkstraShortestPath.java

    package com.company;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;

public class DjikstraShortestPath {
        public void computeShortestPaths(Vertex sourceVertex){

            sourceVertex.setDistance(0);
            PriorityQueue<Vertex> priorityQueue = new PriorityQueue<>();
            priorityQueue.add(sourceVertex);
            sourceVertex.setVisited(true);

            while( !priorityQueue.isEmpty() ){
                // Getting the minimum distance vertex from priority queue
                Vertex actualVertex = priorityQueue.poll();

                for(Edge edge : actualVertex.getAdjacenciesList()){

                    Vertex v = edge.getTargetVertex();
                    if(!v.isVisited())
                    {
                        double newDistance = actualVertex.getDistance() + edge.getWeight();

                        if( newDistance < v.getDistance() ){
                            priorityQueue.remove(v);
                            v.setDistance(newDistance);
                            v.setPredecessor(actualVertex);
                            priorityQueue.add(v);
                        }
                    }
                }
                actualVertex.setVisited(true);
            }
        }

        public List<Vertex> getShortestPathTo(Vertex targetVertex){
            List<Vertex> path = new ArrayList<>();

            for(Vertex vertex=targetVertex;vertex!=null;vertex=vertex.getPredecessor()){
                path.add(vertex);
            }

            Collections.reverse(path);
            return path;
        }

    }

现在,在 Main 我正在尝试这样的事情:

public static void main(String[] args) throws IOException {
{
int i, j;
 DjikstraShortestPath shortestPath = new DjikstraShortestPath();
        shortestPath.computeShortestPaths(vertex[0]); // setting the source to vertex[0]
        for(i=0; i<cities.size(); i++)
        {
            System.out.println("from"+vertex[0]+"to"+vertex[i]+"the distance is" + vertex[i].getDistance());
            System.out.println("Path: "+ shortestPath.getShortestPathTo(vertex[i]));
        }
shortestPath.computeShortestPaths(vertex[1]); //changing the source
for(i=0; i<cities.size(); i++)
        {
            System.out.println("from"+vertex[1]+"to"+vertex[i]+"the distance is" + vertex[i].getDistance());
            System.out.println("Path: "+ shortestPath.getShortestPathTo(vertex[i]));
        }
}

我面临的问题是初始源(初始城市)顶点[0]在设置时会产生正确的结果:

例如:

from A to A the distance is 0.0 //A is the main source in this case vertex[0]
path: A

from A to F the distance is 13.5
path: A D C B F

现在当我将源切换到顶点[1]

from B to A the distance is 0.0 //wrong because it uses the data from the previous (vertex[0])
path: A //this is wrong too

from B to F the distance is 13.5
path: A D C B F //uses the previous info from vertex[0] even though the source is changed to vertex[1]

尝试将 DijkstraShortestPath.java 中的 getShortestPathTo 函数更改为此

public void getShortestPathTo(Vertex targetVertex){
            List<Vertex> path = new ArrayList<>();

            for(Vertex vertex=targetVertex;vertex!=null;vertex=vertex.getPredecessor()){
                path.add(vertex);
            }
            Collections.reverse(path);
            for(int i = 0; i<path.size(); i++)
            {
                System.out.println(path.get(i).getName());
            }
            path.clear();

        }


    }

使所有顶点都未被访问,现在我面临“内存不足”问题。存在堆内存问题,我已经尝试了所有方法。

如有任何帮助,我们将不胜感激。

注意安全,大家待在家里!

最佳答案

在第一次调用 computeShortestPaths 期间,您写入所有已访问的顶点以及它们到源的距离。

在调用 computeShortestPaths 之前,您不会重置此信息,因此顶点会保留其距离和访问过的状态(if(!v.isVisited()) 确保您不要更新第一次调用中已访问过的节点的任何内容)。

因此,您需要清除两次调用之间 Vertex 对象中的所有信息,或者(更好)重构您的代码,以便此信息存储在 DjikstraShortestPath 对象中而不是顶点中,并且每次调用computeShortestPaths时都会重置。

关于java - Java 中的 Dijkstra 算法和源码变更,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60817262/

相关文章:

java - 对象从列表中删除自身的最有效方法

JavaFX布局对齐方式,等同于GridBagLayout

java - 如何检查图像是8位还是16位?

python-3.x - 使用动态规划的数组分区

java - 为什么Java需要变量初始化?

C#:从特定日期添加工作日

algorithm - 当 m 不是素数时,如何找到数字的反模,即 (a%m)

java - Java 的 new 关键字是否一定表示堆分配?

c# - "allocated inline in a structure"对值类型意味着什么?

JAVA : How many Objects will be created ? 为什么?