目录
例如上图,求 V1 到 其他各个顶点的最短路径。
常见的求最短路径的算法有 3 中,分别是 Dijkstra(迪杰斯特拉)、Bellman-Ford算法,Floyd(弗洛伊德)算法其中 Dijkstra 算法是公认的最优的算法。
算法思想
1、Dijkstra:迪杰斯特拉算法是采用贪心算法的思想从初始顶点开始依次向周围扩散,采用广度优先的思想,每一个都可以获取一个点的最短路径,及新的确认点;下一次就从所有确认的点开始,继续执行知道最后一个点也被确认了即可。时间复杂度 O(n);
2、Bellman-Ford:贝尔曼-福特算法思想是,对每一条变进行编号 1 到 n,然后循环遍历即可,遍历方式是从第 1 条边开始计算边的终点数据【终点 = 起点 + 边的权值】,一直到第 n 条边完成 1 次遍历。当图有 m 个顶点时,就需要遍历 m - 1 次才能够保证结果的正确性。
3、Floyd:弗洛伊德算法和前两种算法不同,它可计算每一个顶点到其他的任意顶点的最短距离。其思想就是从任意顶点 i 开始,能不能够借助任意顶点 j 到达其他任意顶点 k ,并且距离小于顶点 i 直接到顶点 k 。具体的请见后面的详细步骤。
实现步骤
1、Dijkstra 算法执行步骤:
a:将图中的所有顶点,起点点的值设置成 0 ,其他的值全部设置成无穷大 (∞),表示每一个顶点到起点的距离。起点为第一个确认点。
b:从第一个确认点出发,按照广度优先遍历向周围扩散,计算邻接点的最短距离,若新的最短距离小于之前的,就更新,此次遍历会找出第二个确认点。
c:按照步骤 b 的方法,从所有的确认点出发,找到第三个,第四个,....,最后一个确认点即可。
上图的确认流程如下
步骤1:初始情况:将 V1 的距离设置成 0 ,其他的为无穷大。
步骤2:获取了第一个确认点 V1,从 V1 出发,计算所有邻接点的最短路径,获取第二个确认点为 V2
步骤3:获取第三个确认点 V3
步骤4:获取确认点 V6
步骤5:获取确认点 V4
步骤6:获取确认点 V5
2、Bellman-Ford 算法执行步骤
步骤1:初始情况下,对所有的边进行编号
步骤2:从第 1 表边开始,按照顺序计算每一个节点的新值,第一次遍历结果如下。
步骤3:继续执行步骤2,直到遍历次数 = 顶点个数 - 1;我们可以发现上图中执行一次就得到了最终正确的结果,这是因为我们对边进行编号是比较幸运,若将上图中编号 8 改为 编号1,就需要继续执行很多遍才会得到正确的结果。
3、Floyd 算法执行步骤
/**
* 如 下面的二位数组,[vi][vj] 表示从上图中 vi 到 vj 的最短距离,初始情况如下。
* v1 v2 v3
* v1 0 4 2
* v2 ∞ 0 1
* v3 2 1 0
*
*
* 步骤1:以 v1 为起点,能否借助 v1 到达其他点。不管
* 步骤2:从 v1 开始,判断能否借助 v2,能够使得 v1 到 vj(j = 1,2,3) 的距离小于初始情况。
* 分析:v1 借助 v2 到达 v1,因为v2 不能到达 v1,不考虑。故 v1 -> v1 = 0.
* v1 借助 v2 到达 v2,结果还是 v1 -> v2 = 4.
* v1 借助 v2 到达 v3,因为 v2 到 v3 为 1,新路线大小为 v1v2 + v2v3 = 4 + 1 = 5 > v1v3 = 2,所以还是用之前的值即可。
* 步骤3:从 v1 开始,判断能否借助 v3,使得 v1 到 vj(j = 1,2,3) 的距离小于初始情况。
* 分析:v1 借助 v3 到达 v1。过
* v1 借助 v3 到达 v2,v1v3 + v3v2 = 3 < v1v2 = 4,所以更新 v1 -> v2 = 3
* v1 借助 v3 到达 v3。过。
* 这样可以得到新的距离数组为:v1v2 变化了
* v1 v2 v3
* v1 0 3 2
* v2 ∞ 0 1
* v3 2 1 0
*
* 步骤4:以 v2 为起点,判断借助 v1 是指能够到达 vj(j = 1,2,3) 的距离小于初始情况。
* 分析:v2 借助 v1 到达 v1,不用管
* v2 借助 v1 到达 v2,不用管
* v2 借助 v1 到达 v3,需要比较。v2v1 + v1v3 = ∞ > v2v3 = 1,过
*
* 步骤5:以 v2 为起点,能否借助 v2 到达其他点。过
*
* 步骤6:以 v2 为起点,能否借助 v3 到达其他点
* 分析:v2 借助 v3 到达 v1, v2v3 + v3v1 = 3 < v2v1 = ∞,所以 v2 -> v1 = 3
* v2 借助 v3 到达 v2,不用管
* v2 借助 v3 到达 v3,不用管
*
* 这样可以得到新的距离数组为:v2v1 变化了
* v1 v2 v3
* v1 0 3 2
* v2 3 0 1
* v3 2 1 0
*
* 步骤7:以 v3 为起点,能否借助 v1 到达其他点
* 分析:v3 借助 v1 到达 v1, 不用管
* v3 借助 v1 到达 v2, v3v1 + v1v2 = 2 + 3 = 5 > v3v2 = 1,过
* v3 借助 v1 到达 v3,不用管
*
*
* 步骤8:以 v3 为起点,能否借助 v2 到达其他点
* 分析:v3 借助 v2 到达 v1, v3v2 + v2v1 = 1 + 3 = 4 > v3v1 = 2,过
* v3 借助 v2 到达 v2, 不用管
* v3 借助 v2 到达 v3,不用管
*
* 步骤9:以 v3 为起点,能否借助 v3 到达其他点,不用管,过
*
* 结束
* 所以得到的最终的结果就是如下:其中任意 [vi][vj] 表示的就是最短距离。
*
* v1 v2 v3
* v1 0 3 2
* v2 3 0 1
* v3 2 1 0
*
*/
从上面的步骤可以看出,弗洛伊德算法的时间复杂度为 O(n^2),n 为图中顶点的个数。