美文网首页技术干货程序员面试
Java 图的最短路径dijstra(迪杰斯特拉)算法和拓扑排序

Java 图的最短路径dijstra(迪杰斯特拉)算法和拓扑排序

作者: 磊_lei | 来源:发表于2018-05-21 21:42 被阅读21次

    一、图的最短路径

    从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径

    图的最短路径

    图的最短路径有许多重要的应用。

    例如:上图中v0-v8有9个点,可以看做不同的地点,现在要规划出v0到其它某个点地点的最短路线规划

    构建最短路径中比较常见的一种算法即为dijstra(迪杰斯特拉)算法

    二、dijstra(迪杰斯特拉)算法

    算法思路:

    1. dijstra算法思路有点类似前一篇文章中的prim算法,先构建图的邻接矩阵,然后定义一个临时的一维数组,一维数组用来存储v0到每个顶点的最短路径
    2. 将一维数组初始化成v0到每个顶点的值。其次定义另外一个数组用来存储已经访问过的顶点
    3. 在临时一维数组中找到未被访问且最短的一条路径
    4. 将找到最短路径的顶点与该顶点可访问边进行遍历,若最短路径与边之和小于一维数组中存储的最短路径,则将这个和覆盖成这个顶点的最短路径
    5. 循环3,4直至遍历完所有顶点为止
    • 构建邻接矩阵
    // 初始化图
    int[] graph0 = new int[]{0, 1, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT};
    int[] graph1 = new int[]{1, 0, 3, 7, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT};
    int[] graph2 = new int[]{5, 3, 0, MAX_WEIGHT, 1, 7, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT};
    int[] graph3 = new int[]{MAX_WEIGHT, 7, MAX_WEIGHT, 0, 2, MAX_WEIGHT, 3, MAX_WEIGHT, MAX_WEIGHT};
    int[] graph4 = new int[]{MAX_WEIGHT, 5, 1, 2, 0, 3, 6, 9, MAX_WEIGHT};
    int[] graph5 = new int[]{MAX_WEIGHT, MAX_WEIGHT, 7, MAX_WEIGHT, 3, 0, MAX_WEIGHT, 5, MAX_WEIGHT};
    int[] graph6 = new int[]{MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 3, 6, MAX_WEIGHT, 0, 2, 7};
    int[] graph7 = new int[]{MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 9, 5, 2, 0, 4};
    int[] graph8 = new int[]{MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 5, 4, 0};
    
    
    • 算法代码
    /**
     * 图的最短路径(图中两个顶点的最短距离),迪杰斯特拉算法
     * 算法思想:类似prim算法,定义一个一维数组,用来存储V0到某点的最短路径
     */
    public void shortestPathDijstra() {
    
        // 定义一维数组用来存储V0到每个点的最短路径,找到比原来更短的则直接覆盖
        int[] paths = new int[vertexSize];
    
        // 先将数组初始化
        System.arraycopy(matrix[0], 0, paths, 0, vertexSize);
    
        isVisited[0] = true;
        for (int i = 1; i < vertexSize; i++) {
    
            // 在已经存在的路径中找到一条未被访问且最短的路径
            int min = MAX_WEIGHT;
            int minIndex = -1;
            for (int j = 1; j < vertexSize; j++) {
                if (!isVisited[j] && paths[j] < min) {
                    min = paths[j];
                    minIndex = j;
                }
            }
    
            if (minIndex == -1) {
                continue;
            }
            isVisited[minIndex] = true;
    
            // 找到的最短路径节点的可使用边中,判断是否比已经存在的最短路径短,是则进行覆盖
            for (int k = 1; k < vertexSize; k++) {
                if (!isVisited[k] && (min + matrix[minIndex][k] < paths[k])) {
                    paths[k] = min + matrix[minIndex][k];
                }
            }
        }
    
        for (int i = 1; i < vertexSize; i++) {
            System.out.println("V0到V" + i + "的最短路径为:" + paths[i]);
        }
    }
    
    • 即可得到v0到每个点的最短路径的值
    dijstra最短路径

    三、拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。

    简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

    对以下有向图进行拓扑排序,顶点可以看待成每项不同的任务,有的任务可以直接执行,例如v0、v1、v3,有的任务得等到上级任务全部执行完成才可执行,例如v4必须等到v0和v1都完成之后才可执行

    拓扑排序

    排序思路:

    1. 观察可以发现顶点入度为0则代表可以直接执行
    2. 完成一个任务之后可消除出度的边,即他的next节点则少了一个入度
    3. 带next节点入度也为0之后就可执行
    4. 循环1,2,3遍历完所有的顶点即可排序完成

    排序代码:

    • 构建每个顶点的邻接表
    拓扑排序邻接点
    • 算法代码
    /**
     * 拓扑排序
     * 思路:定义一个栈,存放入度为0的节点,入度为0则代表可以执行,执行之后则出度的那个节点就减少一个入度,循环直至栈为空
     */
    private void topologicaSort() {
        Stack<Integer> stack = new Stack<>();
    
        // 先将入度为0 的节点压入栈中
        for (int i = 0; i < adjList.length; i++) {
            if (adjList[i].in == 0) {
                stack.push(i);
            }
        }
    
        int count = 0;
        // 循环出栈输出,直至栈为空
        while (!stack.isEmpty()) {
            int index = stack.pop();
            System.out.println("顶点:" + adjList[index].data);
            count++;
            for (EdgeNode edgeNode = adjList[index].firstEdge; edgeNode != null; edgeNode = edgeNode.next) {
                if (--adjList[edgeNode.adjVert].in == 0) {
                    // 若输出之后的顶点入度也没0,则压入栈中
                    stack.push(edgeNode.adjVert);
                }
            }
        }
    
        if (count != numVertexes) {
            System.out.println("拓扑排序失败!!!!");
        }
    }
    

    源码地址

    相关文章

      网友评论

        本文标题:Java 图的最短路径dijstra(迪杰斯特拉)算法和拓扑排序

        本文链接:https://www.haomeiwen.com/subject/tcofjftx.html