迪杰斯特拉算法(计算路径)

Posted rao11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迪杰斯特拉算法(计算路径)相关的知识,希望对你有一定的参考价值。

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

利用递归前置顶点表的方法打印路径

以上是关于迪杰斯特拉算法(计算路径)的主要内容,如果未能解决你的问题,请参考以下文章

图的应用——最短路径(迪杰斯特拉算法)

图论——迪杰斯特拉算法和最小生成树

迪杰斯特拉算法为啥不能有负权边

Dijkstra迪杰斯特拉算法

图(最短路径算法————迪杰斯特拉算法和弗洛伊德算法).RP

bfs输出路径 && 最短路(迪杰斯特拉)输出路径