package com.rao.graph; import java.util.LinkedList; import java.util.List; /** * @author Srao * @className DijkstraWithPath * @date 2019/12/11 17:59 * @package com.rao.graph * @Description 迪杰斯特拉算法(计算路径) */ public class DijkstraWithPath { /** * 图的顶点 */ private static class Vertex{ String data; public Vertex(String data) { this.data = data; } } /** * 图的边 */ private static class Edge{ int index; int weight; public Edge(int index, int weight) { this.index = index; this.weight = weight; } } /** * 图(邻接矩阵) */ private static class Graph{ private Vertex[] vertices; private LinkedList<Edge>[] adj; Graph(int size){ vertices = new Vertex[size]; adj = new LinkedList[size]; for (int i = 0; i < adj.length; i++) { adj[i] = new LinkedList<>(); } } } /** * 初始化图 * @param graph */ private static void initGraph(Graph graph){ graph.vertices[0] = new Vertex("A"); graph.vertices[1] = new Vertex("B"); graph.vertices[2] = new Vertex("C"); graph.vertices[3] = new Vertex("D"); graph.vertices[4] = new Vertex("E"); graph.vertices[5] = new Vertex("F"); graph.vertices[6] = new Vertex("G"); graph.adj[0].add(new Edge(1, 5)); graph.adj[0].add(new Edge(2, 2)); graph.adj[1].add(new Edge(0, 5)); graph.adj[1].add(new Edge(3, 1)); graph.adj[1].add(new Edge(4, 6)); graph.adj[2].add(new Edge(0, 2)); graph.adj[2].add(new Edge(3, 6)); graph.adj[2].add(new Edge(5, 8)); graph.adj[3].add(new Edge(1, 1)); graph.adj[3].add(new Edge(2, 6)); graph.adj[3].add(new Edge(4, 1)); graph.adj[3].add(new Edge(5, 2)); graph.adj[4].add(new Edge(1, 6)); graph.adj[4].add(new Edge(3, 1)); graph.adj[4].add(new Edge(6, 7)); graph.adj[5].add(new Edge(2, 8)); graph.adj[5].add(new Edge(3, 2)); graph.adj[5].add(new Edge(6, 3)); graph.adj[6].add(new Edge(4, 7)); graph.adj[6].add(new Edge(5, 3)); } /** * 迪杰斯特拉算法(计算路径) * @param graph:图 * @param startIndex:起始顶点 * @return 返回前置顶点表 */ public static int[] dijkstra(Graph graph, int startIndex){ //图顶点的数量 int size = graph.vertices.length; //创建距离表,存放每一个点到起始点的最小距离 int[] distances = new int[size]; //创建前置顶点表,存放每一个顶点到起始点的路径中,倒数第二个点的下标 int[] prevs = new int[size]; //记录每个顶点的遍历状态,true为已经访问过 boolean[] access = new boolean[size]; //初始化每一个点到起始点的距离为无穷大 for (int i = 0; i < size; i++) { distances[i] = Integer.MAX_VALUE; } //初始化与初始点相连的点 access[0] = true; List<Edge> edgesFromStart = graph.adj[startIndex]; for (Edge edge : edgesFromStart) { distances[edge.index] = edge.weight; prevs[edge.index] = 0; } //开始循环遍历所有的点 for (int i = 1; i < size; i++) { int minDistanceFromStart = Integer.MAX_VALUE; int minDistanceIndex = -1; for (int j = 1; j < size; j++) { if (!access[j] && distances[j] < minDistanceFromStart){ minDistanceFromStart = distances[j]; minDistanceIndex = j; } } if (minDistanceIndex == -1){ break; } access[minDistanceIndex] = true; for (Edge edge : graph.adj[minDistanceIndex]) { if (access[edge.index]){ continue; } int weight = edge.weight; int preDistance = distances[edge.index]; if (weight !=Integer.MAX_VALUE && (minDistanceFromStart + weight < preDistance)){ distances[edge.index] = minDistanceFromStart + weight; prevs[edge.index] = minDistanceIndex; } } } return prevs; } /** * 输出路径 * @param vertices:图中的所有顶点 * @param prev:前置顶点表 * @param i:从后往前回溯,i的初始值是从起始点到要到达的顶点的下标 */ private static void printPrevs(Vertex[] vertices, int[] prev, int i){ if (i > 0){ printPrevs(vertices, prev, prev[i]); } System.out.println(vertices[i].data); } public static void main(String[] args) { Graph graph = new Graph(7); initGraph(graph); int[] prevs = dijkstra(graph, 0); printPrevs(graph.vertices, prevs, graph.vertices.length-1); } }
利用递归前置顶点表的方法打印路径