简体   繁体   English

使用有向图实现Dijkstra算法

[英]Implementing Dijkstra's Algorithm Using Directed Graphs

I am trying to implement Dijkstra's algorithm using a directed graph via an adjacency list. 我试图通过邻接表使用有向图来实现Dijkstra的算法。 I found some sample code I have been using as an example. 我找到了一些示例代码。 In that code, the graph is populated like this: 在该代码中,图形的填充如下:

private static final Graph.Edge[] GRAPH = {
    new Graph.Edge("a", "b", 7),
    new Graph.Edge("a", "c", 9),
    new Graph.Edge("a", "f", 14),
    new Graph.Edge("b", "c", 10),
    new Graph.Edge("b", "d", 15),
    new Graph.Edge("c", "d", 11),
    new Graph.Edge("c", "f", 2),
   new Graph.Edge("d", "e", 6),
    new Graph.Edge("e", "f", 9),};
private static final String START = "a";
private static final String END = "e";

Since I need to populate from an adjacency list in a text file, I instead tried to do it in this manner: 由于我需要从文本文件的邻接列表中进行填充,因此我尝试以这种方式进行填充:

List<Graph.Edge> list = new ArrayList<>();

    try {
        Scanner scanner = new Scanner(new File(filename));
        while (scanner.hasNextLine()) {
            String source = scanner.findInLine(NAME);
            if (source != null) {
                while (true) {
                    String to = scanner.findInLine(NAME);
                    if (to == null) {
                        break;
                    }
                    int weight = Integer.valueOf(scanner.findInLine(WEIGHT));
                    list.add(new Graph.Edge(source, to, weight));
                }
            }
            scanner.nextLine();
        }
    } catch (FileNotFoundException | NumberFormatException e) {
    }

with

static final Pattern NAME = Pattern.compile("\\w+");
static final Pattern WEIGHT = Pattern.compile("\\d+");

In the sample code, they then run dijkstra's algorithm on the graph in the following way: 在示例代码中,他们然后通过以下方式在图上运行dijkstra的算法:

Graph g = new Graph(GRAPH);
    g.dijkstra(START);
    g.printPath(END);
    g.printAllPaths();

I tried to update my code to work for this implementation of the algorithm. 我尝试更新代码以实现该算法的实现。 I came up with the following: 我想出了以下几点:

try {
        Scanner scanner = new Scanner(new File(filename));

        while (scanner.hasNextLine()) {
            String source = scanner.findInLine(NAME);
            if (source != null) {
                while (true) {
                    String go = scanner.findInLine(NAME);
                    if (go == null) {
                        break;
                    }
                    int weight = Integer.valueOf(scanner.findInLine(WEIGHT));
                    Graph.Edge edge = new Graph.Edge(source, go, weight);

                    Graph g = new Graph(GRAPH);
                    g.dijkstra(source);
                    g.printPath(go);
                }
            }

            scanner.nextLine();
        }
    } catch (FileNotFoundException | NumberFormatException e) {
    }

When I try and run this, it seems to not correctly populate my graph. 当我尝试运行它时,似乎无法正确填充我的图形。 It produces the errors from the dijkstra and printPath method saying that "Graph doesn't contain start/end vertex." 它通过dijkstra和printPath方法产生错误,指出“图形不包含起始/终止顶点”。 How can I update my code so that the graph is correctly populated and able to implement the algorithm correctly? 如何更新代码,以便正确填充图形并能够正确实现算法? Thanks! 谢谢!

EDIT: Here is a sample of my input file 编辑:这是我的输入文件的示例

1 2 1 3 1
2 4 2
3 2 2 5 4
4 3 3 5 3
5 1 4

It follows the format source, adj. 它遵循格式源adj。 vertex, weight, adj. 顶点,重量,调整 vertex, weight.... 顶点,重量...

EDIT 2: Use of Graph.Edge` 编辑2:使用Graph.Edge`

class Graph {

private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges

/**
 * One edge of the graph (only used by Graph constructor)
 */
public static class Edge {

    public final String v1, v2;
    public final int dist;

    public Edge(String v1, String v2, int dist) {
        this.v1 = v1;
        this.v2 = v2;
        this.dist = dist;
    }
}

and

public Graph(Edge[] edges) {
    graph = new HashMap<>(edges.length);

    //one pass to find all vertices
    for (Edge e : edges) {
        if (!graph.containsKey(e.v1)) {
            graph.put(e.v1, new Vertex(e.v1));
        }
        if (!graph.containsKey(e.v2)) {
            graph.put(e.v2, new Vertex(e.v2));
        }
    }

    //another pass to set neighbouring vertices
    for (Edge e : edges) {
        graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
        //graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
    }
}

EDIT: Here is where I found the original sample code from http://rosettacode.org/wiki/Dijkstra%27s_algorithm#Java 编辑:在这里我从http://rosettacode.org/wiki/Dijkstra%27s_algorithm#Java找到原始的示例代码

In order to use the application with file input, use your first file input algorithm . 为了将应用程序与文件输入一起使用 ,请使用第一个文件输入算法 Your second algorithm is useless unless you want to run each line of the file as a Graph with only one Vertex . 除非您想将文件的每一行作为仅带有一个VertexGraph来运行,否则第二种算法是没有用的。

Use your code like this (I've put comments on the lines I've changed): 像这样使用您的代码(我在更改的行上加上了注释):

private static final Graph.Edge[] GRAPH = getEdges("input.txt"); // <-- CHANGED THIS
private static final String START = "1"; // <-- CHANGED THIS
private static final String END = "5"; // <-- CHANGED THIS

private static Graph.Edge[] getEdges(String fileName) { // <-- ADDED THIS
    final Pattern NAME = Pattern.compile("\\w+");
    final Pattern WEIGHT = Pattern.compile("\\d+");
    List<Graph.Edge> list = new ArrayList<>();
    try {
        Scanner scanner = new Scanner(new File(fileName));
        while (scanner.hasNextLine()) {
            String source = scanner.findInLine(NAME);
            if (source != null) {
                while (true) {
                    String to = scanner.findInLine(NAME);
                    if (to == null) {
                        break;
                    }
                    int weight = Integer.valueOf(scanner.findInLine(WEIGHT));
                    list.add(new Graph.Edge(source, to, weight));
                }
            }
            if (scanner.hasNextLine()) // <-- ADDED THIS
                scanner.nextLine();
        }
    } catch (FileNotFoundException | NumberFormatException e) {
    }
    return list.toArray(new Graph.Edge[0]); // <-- ADDED THIS
}

Then, run the application the same way: 然后,以相同方式运行应用程序:

Graph g = new Graph(GRAPH);
g.dijkstra(START);
g.printPath(END);
g.printAllPaths();

I tested all of this, and also found that your algorithm for file input breaks on the last line of the file, so I added if (scanner.hasNextLine()) before scanner.nextLine(); 我测试了所有这些,还发现您的文件输入算法在文件的最后一行中断,因此我if (scanner.hasNextLine())之前添加了if (scanner.hasNextLine()) scanner.nextLine();

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

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