实现 Dijkstra 的 Java 程序不读取 txt 文件
Posted
技术标签:
【中文标题】实现 Dijkstra 的 Java 程序不读取 txt 文件【英文标题】:Java program to implement Dijkstra not reading txt file 【发布时间】:2021-12-24 12:38:13 【问题描述】:这是我的 Dijkstra 实现,基于类中提供的伪代码。 (这是一个学校作业,但是这个项目已经被队友上交了。我只是想弄清楚为什么我的版本不起作用。)
当我使用与 txt 文件相同的图形信息创建自己的图形时,它会为我提供正确的输出 - 从给定源到每个顶点的最短路径。当我读入文本文件时,它没有。它读入文件并打印正确的邻接列表,但没有给出最短路径。
这是在文件上运行时出错的地方:在第一次放松的迭代中,它更新了相邻顶点距离和父节点,但返回到 dijkstra 方法并且不再更新距离/父节点。这是为什么呢?
提供的 txt 文件如下所示: 4 0 1,1 3,2 1 2,4 2 1,6 4,7 3 0,3 1,9 2,2 4 0,10 3,5
对不起,如果这是一团糟,我正在学习!
import java.util.PriorityQueue;
import java.util.Collections;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.io.IOException;
/** Class to implement Dijkstra algorithm.
* Includes classes for Vertex, Edge and Graph.
*/
public class Dijkstra
private LinkedList<Vertex> shortestPath;
private LinkedList<Vertex> path;
private PriorityQueue<Vertex> pq;
private PriorityQueue<Vertex> pq2;
static final int INFINITY = Integer.MAX_VALUE;
/** Main method reads in a txt file and prints
* the shortest path to each vertex from a given source.
* @throws FileNotFoundException
* @throws IOException
*/
public static void main(String[] args) throws FileNotFoundException,
IOException
// ourGraph is a sample graph to test output
// vertices and edges are the same as txt file
Vertex v0 = new Vertex("0");
Vertex v1 = new Vertex("1");
Vertex v2 = new Vertex("2");
Vertex v3 = new Vertex("3");
Vertex v4 = new Vertex("4");
Graph ourGraph = new Graph(v4);
ourGraph.addVertex(v0);
ourGraph.addVertex(v1);
ourGraph.addVertex(v2);
ourGraph.addVertex(v3);
ourGraph.addVertex(v4);
ourGraph.addEdge(v0, v1, 1);
ourGraph.addEdge(v0, v3, 2);
ourGraph.addEdge(v1, v2, 4);
ourGraph.addEdge(v2, v1, 6);
ourGraph.addEdge(v2, v4, 7);
ourGraph.addEdge(v3, v0, 3);
ourGraph.addEdge(v3, v1, 9);
ourGraph.addEdge(v3, v2, 2);
ourGraph.addEdge(v4, v0, 10);
ourGraph.addEdge(v4, v3, 5);
ourGraph.printGraph(); // prints correct output
Dijkstra d = new Dijkstra();
d.getDijkstra(ourGraph, v4); // runs Dijkstra with v4 as source
for (Vertex v : ourGraph.nodes)
d.printShortestPath(ourGraph, v); // correct output for shortest paths
Scanner scanner = new Scanner(System.in);
System.out.print("Please enter file name: ");
String fileName = scanner.nextLine();
Scanner file = new Scanner(new File(fileName));
String sourceID = file.nextLine();
Graph g = new Graph(new Vertex(sourceID));
while (file.hasNext())
String[] currentLine = file.nextLine().split(" |,");
Vertex vertex = new Vertex(currentLine[0]);
g.addVertex(vertex);
// set the graph's source vertex
if (vertex.getName().equals(sourceID))
g.source = vertex;
// read current line for adjacent vertices and their edge weights
for (int i = 1; i < currentLine.length; i++)
g.addEdge(vertex, new Vertex(currentLine[i]),
Integer.parseInt(currentLine[++i]));
g.printGraph(); // prints expected graph
Dijkstra d2 = new Dijkstra();
d2.getDijkstra(g, g.source);
for (Vertex vx : g.nodes)
d2.printShortestPath(g, vx);
/* Vertex class with fields for name, parent,
* distance, and edge list.
*/
static class Vertex implements Comparable<Vertex>
private String name;
private Vertex p;
private int d;
private LinkedList<Edge> edgeList;
Vertex(String n)
this.name = n;
this.p = null;
this.d = INFINITY;
edgeList = new LinkedList<>();
public String getName()
return name;
public LinkedList<Edge> getEdges()
return edgeList;
@Override
public int compareTo(Vertex other)
return Integer.compare(this.d, other.d);
static class Edge
private int weight;
private Vertex source;
private Vertex destination;
Edge(Vertex d, int w)
this.destination = d;
this.weight = w;
public int getWeight()
return weight;
public Vertex getSource()
return source;
public Vertex getDestination()
return destination;
static class Graph
private LinkedList<Vertex> nodes;
private Vertex source;
Graph(Vertex s)
nodes = new LinkedList<>();
this.source = s;
public void addSource(Vertex s)
this.source = s;
public void addEdge(Vertex s, Vertex d, int weight)
s.getEdges().add(new Edge(d, weight));
public void addVertex(Vertex v)
nodes.add(v);
public void printGraph()
for (Vertex v : nodes)
System.out.print("vertex: " + v.getName() + ": ");
for (Edge e : v.getEdges())
System.out.print(e.getDestination().getName()
+ "," + e.getWeight() + " ");
System.out.print("\n");
/** method to calculate shortest path using
* Dijkstra's algorithm.
* @param graph with vertices and edges
* @param source as starting vertex
* @return a LinkedList of vertices as shortest path
*/
public LinkedList<Vertex> getDijkstra(Graph graph, Vertex source)
initializeSingleSource(graph, source);
shortestPath = new LinkedList<Vertex>();
pq = new PriorityQueue<Vertex>();
pq.addAll(graph.nodes);
while (!pq.isEmpty())
// used a second pq to re-min-heapify after min is removed
pq2 = new PriorityQueue<Vertex>();
pq2.addAll(pq);
Vertex u = pq2.poll();
if (!shortestPath.contains(u))
shortestPath.add(u);
for (Edge e : u.getEdges())
relax(u, e.getDestination(), e.getWeight());
pq.remove(u);
return shortestPath;
/** initializes each vertex distance to infinity and
* each parent to null. Sets source distance to 0.
* @param graph for input
* @param source is source vertex of graph
*/
public void initializeSingleSource(Graph graph, Vertex source)
for (Vertex v : graph.nodes)
v.d = INFINITY;
source.d = 0;
/** Relax checks if the distance of the destination
* vertex is greater than the distance of the start plus
* the edge weight and updates distance and parent attributes.
* @param u vertex is start
* @param v is destination vertex
* @param weight is edge weight
*/
public void relax(Vertex u, Vertex v, int weight)
if (v.d > u.d + weight)
v.d = u.d + weight;
v.p = u;
/** getPath puts shortest path in order for a given target.
* @param g for graph input
* @param target is target vertex of shortest path from the
* graph's source
* @return LinkedList of shortest path
*/
public LinkedList<Vertex> getPath(Graph g, Vertex target)
LinkedList<Vertex> path = new LinkedList<Vertex>();
Vertex step = target;
int i = shortestPath.indexOf(step);
while (step.p != null)
path.add(step);
step = step.p;
Collections.reverse(path);
return path;
/** prints a formatted list of a single vertex's shortest path.
* from the graph's source
* @param g is graph
* @param target is target vertex of shortest path
*/
public void printShortestPath(Graph g, Vertex target)
shortestPath = getPath(g, target);
System.out.print(target.getName() + ": ");
for (Vertex v : shortestPath)
System.out.print(v.getName() + " ");
System.out.print("\n");
【问题讨论】:
【参考方案1】:首先文件结构如下:
4
0 1,1 3,2
1 2,4
2 1,6 4,7
3 0,3 1,9 2,2
4 0,10 3,5
现在你的问题在这里,这个问题的原因是在读取文件时创建了新的顶点:
while (file.hasNext())
String[] currentLine = file.nextLine().split(" |,");
Vertex vertex = new Vertex(currentLine[0]);
g.addVertex(vertex);
// set the graph's source vertex
if (vertex.getName().equals(sourceID))
g.source = vertex;
// read current line for adjacent vertices and their edge weights
for (int i = 1; i < currentLine.length; i++)
g.addEdge(vertex, new Vertex(currentLine[i]),
Integer.parseInt(currentLine[++i]));
当你这样做时:
g.addEdge(vertex, new Vertex(currentLine[i]), Integer.parseInt(currentLine[++i]));
在这里,您创建一个名为 currentLine[i]
的新顶点,即使图中已经存在同名的顶点,它也会创建一个新顶点,并且不会神奇地重用现有顶点。
要解决此问题,请在 Graph
类中添加一个函数,例如按名称获取现有顶点或在未找到时创建一个。
在您的Graph
类中添加以下方法:
public Vertex getOrCreateVertex(String name)
for (Vertex v : nodes)
if (v.name.equals(name))
return v;
Vertex newVertex = new Vertex(name);
nodes.add(newVertex);
return newVertex;
并将读取文件的部分更改如下:
while (file.hasNext())
String[] currentLine = file.nextLine().split(" |,");
Vertex vertex = g.getOrCreateVertex(currentLine[0]);
// set the graph's source vertex
if (vertex.getName().equals(sourceID))
g.source = vertex;
// read current line for adjacent vertices and their edge weights
for (int i = 1; i < currentLine.length; i++)
g.addEdge(vertex, g.getOrCreateVertex(currentLine[i]),
Integer.parseInt(currentLine[++i]));
【讨论】:
太棒了,做到了。谢谢@b.GHILAS!以上是关于实现 Dijkstra 的 Java 程序不读取 txt 文件的主要内容,如果未能解决你的问题,请参考以下文章