迪杰斯特拉算法

算法概述

迪杰斯特拉算法解决了如何在一个图中,计算某一个节点到图中其他所有节点的最短路径。如果将全国所有城市当做节点,连接两个城市的铁路当做线,那么迪杰斯特拉算法可以求出,厦门到全国其他城市的最省时的出行路线。

维基百科中的专业描述

算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。我们以 V 表示 G 中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u, v) 表示从顶点 u 到 v 有路径相连。我们以 E 表示G中所有边的集合,而边的权重则由权重函数 w: E → [0, ∞] 定义。因此,w(u, v) 就是从顶点 u 到顶点 v 的非负权重(weight)。边的权重可以想像成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t 的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。

算法描述

  1. 将图中的顶点分为两个部分,一个是已知最短路径的顶点,记为集合P,一个是暂时还未知最短路径的顶点,记为集合Q。数组ds[i],表示源点到顶点i的最短路径,数组e[i][j]表示顶点i到j的距离
  2. 初始时,集合P中只有源点S,ds[0]=0,然后从集合Q中,找到离源点S最近的顶点u,并将u加入到集合P中。然后判断所有以u为起点的边,假设存在边uv,如果e[s][u] + e[u][v] < e[s][v], 则更新源点S到顶点v的最短路径
  3. 重复步骤2,直到集合Q为空,算法结束

算法示例

  1. 初始时,集合P={1},Q={2,3,4,5,6}, ds={0,-,-,-,-,-},-表示距离无穷大
  2. 在Q中找到离顶点1最近的点,可以看到是顶点2,于是P={1,2}, Q={3,4,5,6} ds={0,1,12,-,-,-}
  3. 更新所有以顶点2为起点的边(e[2][3],e[2][4]),因为e[1][2] + e[2][3] < e[1][3],所以更新ds[3]=10, 同理e[1][2] + e[2][4] < e[1][4], 所以更新ds[4]=4
  4. 在Q中找到离顶点2最近的点,可以看到是顶点4,于是P={1,2,4}, Q={3,5,6},在更新所有以顶点4为起点的边
  5. 重复上述过程

代码实现

package com.wbl;

import java.util.Arrays;
import java.util.stream.StreamSupport;

/**
 * @author wbl
 * @date 2019-06-30
 */
public class Dijkstra {
    public int[] dijkstra(int[][] edge){
        int[] ds = new int[edge.length];
        //初始化最短路径,这里假设都是计算从顶点1到其他顶点的最短路径
        for (int i = 1; i < ds.length; i++){
            ds[i] = Integer.MAX_VALUE;
        }
        //用来标志以找到最短路径的顶点,若flag[i] = 1,则表示已经找到由源点到顶点i的最短路径
        int[] flag = new int[edge.length];
        for (int i = 0; i < edge.length; i++){
            int minIndex = 0;
            int minValue = Integer.MAX_VALUE;
            // 找到离已知顶点最近的顶点,minIndex表示该顶点
            for (int j = 0; j < edge.length; j++){
                if (flag[j] == 0 && ds[j] < minValue){
                    minValue = ds[j];
                    minIndex = j;
                }
            }
            flag[minIndex] = 1;
            for (int k = 0; k < edge.length; k++){
                // 收敛源点到各个顶点的距离
                if (edge[minIndex][k]>0 && ds[minIndex] + edge[minIndex][k] < ds[k]){
                    ds[k] = ds[minIndex] + edge[minIndex][k];
                }
            }
        }
        return ds;
    }

    public static void main(String[] args) {
        int [][] edge = new int[][]{
                {0,1,12,-1,-1,-1},
                {-1,0,9,3,-1,-1},
                {-1,-1,0,-1,5,-1},
                {-1,-1,4,0,13,15},
                {-1,-1,-1,-1,0,4},
                {-1,-1,-1,-1,-1,0},
        };
        Dijkstra dijkstra = new Dijkstra();
        System.out.println(Arrays.toString(dijkstra.dijkstra(edge)));
    }
}

参考文献

  1. Dijkstra 最短路算法
  2. 戴克斯特拉算法

Reprint please specify: wbl 迪杰斯特拉算法

Previous
Floyd算法 Floyd算法
算法概述弗洛伊德算法,是解决任意两点间的最短路径的一种算法。它的时间复杂度为 O(N^3)空间复杂度为 O(N^2)。 算法描述弗洛伊德算法其实采用的是动态规划 设F(i,j,k)表示节点i到节点j只以(1,k)之间的节点作为中间节点的最短
Next
初探Select,Poll,Epoll 初探Select,Poll,Epoll
在一个高性能的网络服务中,一个进程往往需要同时处理多个socket。在上一篇博客Linux IO模型中提到的IO多路复用模型就是为了解决这个问题的。 Select,Poll,EPoll是IO多路复用的三种机制,下面来具体看下三者之间的联系和