[英]Java program to implement Dijkstra not reading txt file
這是我基於類中提供的偽代碼實現的 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");
}
}
首先文件的結構如下:
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]));
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.