用有向图实现Dijkstra算法

时间:2016-03-26 18:08:36

标签: java graph dijkstra directed-graph adjacency-list

我试图通过邻接列表使用有向图来实现Dijkstra算法。我找到了一些我一直在使用的示例代码作为示例。在该代码中,图形填充如下:

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";

由于我需要从文本文件中的邻接列表填充,我试图以这种方式进行填充:

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) {
    }

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

在示例代码中,他们以下列方式在图表上运行dijkstra算法:

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

我尝试更新我的代码以适用于此算法的实现。我想出了以下内容:

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) {
    }

当我尝试运行它时,似乎没有正确填充我的图表。它从dijkstra和printPath方法产生错误,说“Graph不包含开始/结束顶点”。如何更新我的代码以便正确填充图表并能够正确实现算法?谢谢!

编辑:以下是我输入文件的示例

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

它遵循格式源,adj。顶点,重量,adj。顶点,重量......

编辑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;
    }
}

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
    }
}

编辑:我在这里找到了来自http://rosettacode.org/wiki/Dijkstra%27s_algorithm#Java

的原始示例代码

1 个答案:

答案 0 :(得分:1)

为了使用带有文件输入的应用程序,使用您的第一个文件输入算法。除非您希望将文件的每一行作为Graph运行且只有一个Vertex,否则您的第二个算法将无用。

像这样使用你的代码(我已经对我改变的行添加了评论):

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
}

然后,以相同的方式运行应用程序:

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

我测试了所有这些,并且还发现您的文件输入算法在文件的最后一行中断,所以我在if (scanner.hasNextLine())之前添加了scanner.nextLine();