java - 使用有向图实现 Dijkstra 算法

标签 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 方法中产生错误,指出“图形不包含开始/结束顶点”。如何更新我的代码以便正确填充图表并能够正确实现算法?谢谢!

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

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

它遵循格式来源,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 找到原始示例代码的地方

最佳答案

为了使用带有文件输入的应用程序,使用您的第一个文件输入算法。除非您想将文件的每一行作为只有一个顶点Graph来运行,否则您的第二个算法是无用的。

像这样使用你的代码(我已经在更改的行上添加了注释):

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();

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

关于java - 使用有向图实现 Dijkstra 算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36238913/

相关文章:

java - DocumentFilter 不监听变化怎么办?

java - LIBGDX:如何水平/垂直翻转相机 View ?

algorithm - 如何生成具有均匀分布的随机 DFA?

algorithm - Dijkstra 与迭代。如何对图建模并确定两种情况下的时间复杂度?

java - Set<Set> Java 中的相等性

java - 如何在ListView中显示HashMap中的项目和子项目

algorithm - 找到一条通过任意节点序列的最短路径?

uitableview - 在 UITableView 中设置 BEMSimpleLineGraph Plot

algorithm - Dijkstra 算法在寻找最短路径方面比 AN* 算法有何优势?

c++ - 将 Dijkstra 算法与 unordered_map 图结合使用