Loading

45-Dijkstra算法

应用场景:

1. 算法概述

  • Dijkstra算法 是典型单源最短路径算法,用于计算一个顶点到其他顶点的最短路径
    • 单源:从一个顶点出发,Dijkstra算法 只能求一个顶点到其他点的最短距离而不能任意两顶点
    • 用于无权图,或者所有边的权都相等的图,Dijkstra 算法等同于BFS搜索
  • 特点:以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止
  • Dijkstra算法 用于对有权图进行搜索,找出图中两点的最短距离,既不是DFS搜索,也不是BFS搜索

2. 基本思想

  • 设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组
    • 第 1 组为已求出最短路径的顶点集合 (用S表示),初始时S中只有一个起点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了
    • 第 2 组为其余未确定最短路径的顶点集合 (用U表示),按最短路径长度的递增次序依次把第 2 组的顶点加入S中,在加入的过程中,总保持从起点s到S中各顶点的最短路径长度不大于从起点s到U中任何顶点的最短路径长度
  • 此外,每个顶点对应一个距离
    • S中的顶点的距离就是从v到此顶点的最短路径长度
    • U中的顶点的距离,是从v到此顶点 只包括S中的顶点为中间顶点 的当前最短路径长度
  • 初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是"起点s到该顶点的路径"。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径
  • 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。重复该操作,直到遍历完所有顶点

3. 操作演示

https://blog.csdn.net/kprogram/article/details/81225176
https://zhuanlan.zhihu.com/p/40338107

  • 实际上,Dijkstra 算法是一个排序过程,就上面的例子来说,是根据D到图中其余点的最短路径长度进行排序,路径越短越先被找到,路径越长越靠后才能被找到
  • 可见,要找D到A的最短路径,我们依次找到了:
    • D → C 的最短路径 3
    • D → E 的最短路径 4
    • D → E → F 的最短路径 6
    • D → E → G 的最短路径 12
    • D → C → B 的最短路径 13
    • D → E → F → A 的最短路径 22

4. 代码实现

public class DijkstraAlgorithm {
    public static void main(String[] args) {
        char[] vertexs = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
        int[][] matrix = new int[vertexs.length][vertexs.length];
        final int N = 65535; // 表示不可以连接
        matrix[0]=new int[]{N,5,7,N,N,N,2};  
        matrix[1]=new int[]{5,N,N,9,N,N,3};
        matrix[2]=new int[]{7,N,N,N,8,N,N};
        matrix[3]=new int[]{N,9,N,N,N,4,N};
        matrix[4]=new int[]{N,N,8,N,N,5,4};
        matrix[5]=new int[]{N,N,N,4,5,N,6};
        matrix[6]=new int[]{2,3,N,N,4,6,N};
        Graph graph = new Graph(vertexs, matrix);
        graph.dijkstra(2); // C
        graph.showShortestPath();
    }
}

class VisitedVertex {
    int[] alreadyArr; // 记录已访问顶点
    int[] preVisited; // 各个顶点的前驱顶点
    int[] dis; // 起点到各个顶点的距离
    
    public VisitedVertex(int length, int index) {
        alreadyArr = new int[length];
        alreadyArr[index] = 1;
        preVisited = new int[length];
        dis = new int[length];
        // 初始化 dis[]
        for(int i = 0; i < length; i++)
            dis[i] = 65535;
        dis[index] = 0; // 出发顶点的访问距离为0
    }
    
    /**
     * 判断 顶点index 是否被访问过
     * @param index
     * @return 如果访问过返回true; 反之false
     */
    public boolean isVisited(int index) {
        return alreadyArr[index] == 1;
    }
    
    /**
     * 更新 出发顶点 到 顶点index 的距离为len
     * @param index
     * @param len
     */
    public void updateDis(int index, int len) {
        dis[index] = len;
    }
    
    /**
     * 更新 顶点index 的前驱 为 preV
     * @param index 顶点
     * @param preV 顶点的前驱
     */
    public void updatePreVertex(int index, int preV) {
        preVisited[index] = preV;
    }
    
    /**
     * 返回 出发顶点 到 顶点index 的距离
     * @param index
     */
    public int getDis(int index) {
        return dis[index];
    }
    
    // 选择新的访问顶点
    public int getVisitVertex() {
        int min = 65535, index = 0;
        for(int i = 0; i < alreadyArr.length; i++)
            if(alreadyArr[i] == 0 && dis[i] < min) {
                min = dis[i];
                index = i;
            }
        // 设置 顶点index 为 已访问
        alreadyArr[index] = 1;
        return index;
    }
}

class Graph {
    char[] vertexs;
    int[][] matrix;
    VisitedVertex vv;
    
    public Graph(char[] vertexs, int[][] matrix) {
        super();
        this.vertexs = vertexs;
        this.matrix = matrix;
    }
    
    /**
     * 求单源最短路径
     * @param index 出发顶点的索引
     */
    public void dijkstra(int index) {
        vv = new VisitedVertex(vertexs.length, index);
        update(index); // {出发顶点}
        for(int j = 1; j < vertexs.length; j++) {
            index = vv.getVisitVertex();
            update(index); // {访问顶点}
        }
    }

    // 更新 顶点index 到周围顶点的距离 及 周围顶点的前驱顶点
    private void update(int index) {
        int len = 0;
        // 遍历: 顶点index 连接关系的那一行
        for(int j = 0; j < matrix[index].length; j++) {
            // 出发顶点 经 顶点index 到 顶点j 的距离
            len = vv.getDis(index) + matrix[index][j];
            if(!vv.isVisited(j) && len < vv.getDis(j)) {
                vv.updatePreVertex(j, index);
                vv.updateDis(j, len);
            }
        }
    }
    
    public void showShortestPath() {
        for(int i = 0; i < vv.dis.length; i++)
            System.out.printf("%c(%d) ", vertexs[i], vv.dis[i]);
    }
}
posted @ 2020-04-01 13:04  tree6x7  阅读(146)  评论(0编辑  收藏  举报