目录

一、什么是最短路径?

二、实现最短路径的2种算法?

三、最短路径

1、某个顶点到其余各顶点的最短路径:迪 杰斯特拉(Dijkstra)算法

2、每一对顶点之间的最短路径: 佛洛依德(Floyed) 算法

四、练习


一、什么是最短路径?

最短路径问题是指在一个赋权图的两个节点之间找出一个具有最小权的路径。旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。

现实生活中我们可用看到许多最短路径问题的例子:

  1. 如公交车辆的最优行驶路线和旅游线路的选择。
  2. 军事领域中,作战部队的行军陆路线。
  3. 救护车、消防车等救援车辆采取最短行驶路线火速赶往现场。

以上等问题,都是在寻找一个的最短路径作为最优选择;而这就与寻找一个图的最短路径密切相关。


二、实现最短路径的2种算法?

用于解决最短路径问题的算法被称做“最短路径算法”, 有时被简称作“路径算法”。

最常用的路径算法有:

1、迪 杰斯特拉(Dijkstra)算法:

求单源最短路径的。

从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

2、佛洛依德(Floyed) 算法:

是解决任意两点间的最短路径的一种算法,用来求图中所有点对之间的最短路径。

三、最短路径

1、某个顶点到其余各顶点的最短路径:迪 杰斯特拉(Dijkstra)算法

1)概述

  • 网经常用于描述一个城市或城市间的交通运输网络。

    • 以顶点表示一个城市或某个交通枢纽

    • 以边表示两地之间的交通状况

    • 边上的权值表示各种相关信息

  • 当两个顶点之间存在多条路径时,其中必然存在一条“最短路径”

  • 名词:

    • 源点(Source):路径中的第一个顶点

    • 终点(Destination):最后一个顶点

2)实例

从源点v0到终点v5存在多条路径:

v0, v5) 的长度为 100

(v0, v4, v5) 的长度为 90

(v0,v4,v3 v5) 的长度为 60   //最短路径

(v0, v2,v3, v5) 的长度为 7

从源点v0到各终点的最短路径:

v0到终点v1不存在路径

(v0,v2) 的最短路径长度为10

(v0,v4,v3) 的最短路径长度为50

(v0,v4) 的最短路径长度为30

(v0,v4,v3,v5) 的最短路径长度为60

3)迪杰斯特拉(Dijkstra)算法:概述

  • 算法描述:

    1.用于求解某个源点到其余各顶点的最短路径。

    2.按最短路径长度递增的次序求解

    3.类似于普利姆算法

  • 每一条最短路径必定只有两种情况:

    1.由源点直接到达终点

    2.只经过已经求得最短路径的顶点到达终点

  • 迪杰斯特拉算法解决的问题:如何实现“按最短路径长度递增的次序”求解

  • 解决方法:

    1.每次选出当前的一条最短路径

    2.算法中需要引入一个辅助向量D,它的每个分类D[i]存放当前所找到的从源点到各个终点vi的最短路径长度。

4)迪杰斯特拉(Dijkstra)算法:算法分析

  1. 初始若从源点v到各个终点有弧,则存在一条路径,路径长度即为该弧上的权值,保存于D中

  2. 求得一条到达某个终点的最短路径,即当前路径中的最小值,该顶点即为w

  3. 检查是否存在经过顶点w的其他路径,若存在,判断其长度是否比当前求得的路径长度短,若是,则修改D中当前最短路径。

  4. 重复上面的2和3

5)迪杰斯特拉(Dijkstra)算法:代码实现

测试数据:

处理后的数组P的内容:

处理后数组D的内容:

算法代码实现:

public class ShortestPath_DIJ {private boolean[][] P;// v0到其余顶点的最短路径, 若P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点private int[] D;// v0到其余顶点的带权长度public final static int INFINITY = Integer.MAX_VALUE;// 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及其权值D[v]public void DIJ(MGraph G, int v0) {int vexNum = G.getVexNum();P = new boolean[vexNum][vexNum];  // 用于记录经过的顶点D = new int[vexNum];               // 用于记录到达某顶点需要的最短路径和boolean[] finish = new boolean[vexNum];// finish[v]为true当且仅当v属于S,即已经求得从v0到v的最短路径// 数据初始化for (int v = 0; v < vexNum; v++) {finish[v] = false;D[v] = G.getArcs()[v0][v];     // D 记录v0到所有各个边的权值for (int w = 0; w < vexNum; w++)P[v][w] = false;           // 设空路径,及设置默认值if (D[v] < INFINITY) {P[v][v0] = true;         // 在P数组的第v行,标记v0被访问P[v][v] = true;              // 在P数组的第v行,标记邻接点被访问}}D[v0] = 0;// 初始化,v0顶点属于S集finish[v0] = true;int v = -1;// 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集for (int i = 1; i < vexNum; i++) {// 其余G.getVexNum-1个顶点int min = INFINITY;// 当前所知离v0顶点的最近距离for (int w = 0; w < vexNum; w++)if (!finish[w])if (D[w] < min) {v = w;min = D[w];}finish[v] = true;// 离v0顶点最近的v加入S集for (int w = 0; w < vexNum; w++)// 更新当前最短路径及距离if (!finish[w] && G.getArcs()[v][w] < INFINITY&& (min + G.getArcs()[v][w] < D[w])) { // 修改D[w]和P[w],w属于V-SD[w] = min + G.getArcs()[v][w];// w在v的基础上继续前行,所以将v经过的内容拷贝到w上System.arraycopy(P[v], 0, P[w], 0, P[v].length);P[w][w] = true;}}}public int[] getD() {return D;}public boolean[][] getP() {return P;}public static void main(String[] args) throws Exception {MGraph G = GenerateGraph.generateMGraph();ShortestPath_DIJ dij = new ShortestPath_DIJ();dij.DIJ(G, 0);dij.display(G);}// 用于输出最短路径上的各个顶点及权值public void display(MGraph G) throws Exception {if (D != null) {System.out.println("各个顶点到v0的最短路径上的点及最短距离分别是:");for (int i = 0; i < P.length; i++) {System.out.print("v0 - " + G.getVex(i) + ": ");for (int j = 0; j < P[i].length; j++) {if (P[i][j])System.out.print(G.getVex(j) + "\t");}System.out.println("最短距离为: " + D[i]);}}}}// 调试结果:
// 各个顶点到v0的最短路径上的点及最短距离分别是:
// v0 - v0: v0 最短距离为: 0
// v0 - v1: v0 v1 最短距离为: 7
// v0 - v2: v0 v2 最短距离为: 1
// v0 - v3: v0 v3 最短距离为: 5
// v0 - v4: v0 v2 v4 最短距离为: 7
// v0 - v5: v0 v2 v5 最短距离为: 5

6)迪杰斯特拉(Dijkstra)算法:性能分析

  • 算法的时间复杂度:O(n2)

  • 找一条从源点到某一特定终点之间的最短路径问题和求源点到各个终点的最短路径一样复杂,其时间复杂度仍为O(n2)

  • 若希望得到图中任意两个顶点之间的最短路径,只要依次将每一个顶点设为源点,并调用迪杰斯特拉算法,其时间复杂度为 O(n3)


2、每一对顶点之间的最短路径: 佛洛依德(Floyed) 算法

1)概述

  • 若希望得到图中任意两个定点之间的最短路径,只要依次将每一个定点设为源点,调用迪杰斯克拉算法n次便可求得,其时间复杂度为O(n3) 。

  • 佛洛依德(Floyed)提出了另外一个算法,虽然时间复杂度也是O(n3),但是算法的形式更为简单。

2)佛洛依德(Floyed) 算法:概述

  • D是路径长度序列

  • P是路径序列

    1. 求的一个n阶方阵序列:D(-1),D(0),D(1),D(2),... ,D(k),...,D(n-1)

    2. D(-1)[i][j]表示从顶点vi出发,不经过其他顶点【直接】到达顶点vj的路径长度。

    3. D(k)[i][j]表示从顶点vi到vj的中间只可能经过v0,v1,....,vk , 而不可能经过 vk+1,vk+2, ... ,vn-1等顶点的最短路径长度。

    4. D(n-1)[i][j]表示从顶点vi到顶点vj的最短路径的长度。

3)佛洛依德(Floyed) 算法:算法分析

  • 算法关键操作
// k 表示在路径中新增的顶点号
// i 表示路径的源点
// j 表示路径的终点
if(D[i][k] + D[k][j] < D[i][j]) {D[i][j] = D[i][k] + D[k][j];     //更新最短路径长度P[i][j] = P[i][k] + P[k][j];        //更新最短路径
}
  • 有向图

4)佛洛依德(Floyed) 算法:代码实现

  • 类似于对每一个顶点进行迪杰斯特拉算法。

  • 算法代码实现:
public class ShortestPath_FLOYD {private boolean[][][] P;// 顶点v和w之间的最短路径P[v][w],若P[v][w][u]为true,则u是从v到w当前求得最短路径上的顶点private int[][] D;// 顶点v和w之间最短路径的带权长度D[v][w]public final static int INFINITY = Integer.MAX_VALUE;// 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及其权值D[v]public void FLOYD(MGraph G) {int vexNum = G.getVexNum();P = new boolean[vexNum][vexNum][vexNum];D = new int[vexNum][vexNum];for (int v = 0; v < vexNum; v++) // 各对结点之间初始化已知路径及距离for (int w = 0; w < vexNum; w++) {D[v][w] = G.getArcs()[v][w];for (int u = 0; u < vexNum; u++)P[v][w][u] = false;if (D[v][w] < INFINITY) {// 从v到w有直接路径P[v][w][v] = true;P[v][w][w] = true;}}for (int u = 0; u < vexNum; u++)for (int v = 0; v < vexNum; v++)for (int w = 0; w < vexNum; w++)if (D[v][u] < INFINITY && D[u][w] < INFINITY&& D[v][u] + D[u][w] < D[v][w]) { // 从v经u到w的一条路径最短D[v][w] = D[v][u] + D[u][w];for (int i = 0; i < vexNum; i++)P[v][w][i] = P[v][u][i] || P[u][w][i];}}public int[][] getD() {return D;}public boolean[][][] getP() {return P;}
}
  • 测试程序:

public class Example6_5_G9 {public final static int INFINITY = Integer.MAX_VALUE;public static void main(String[] args) throws Exception {Object vexs[] = { "v0", "v1", "v2" };int[][] arcs = { { 0, 4, 11},{ 6, 0, 2},{ 3, INFINITY,0}};MGraph G = new MGraph(GraphKind.DN, vexs.length, 5, vexs, arcs);ShortestPath_FLOYD floyd = new ShortestPath_FLOYD();floyd.FLOYD(G);display(floyd.getD());}// 输出各村的最短路径长度public static void display(int[][] D) {System.out.println("各顶点之间的最短路径长度为:");for (int v = 0; v < D.length; v++) {for (int w = 0; w < D.length; w++)System.out.print(D[v][w] + "\t");System.out.println();}}}
// 调试结果:
//各顶点之间的最短路径长度为:
//      0   4   6
//      5   0   2
//      3   7   0

5)佛洛依德(Floyed) 算法:性能分析

  • 算法复杂度仍为O(n3)

  • 是解决任意两点间的最短路径的一种算法

  • 求单源点无负边最短路径用Dijkstra,而求所有点最短路径用Floyd且Floyd可以处理带负边的图。

  • 对于稀疏的图,采用n次Dijkstra比较出色,对于茂密的图,可以使用Floyd算法。

  • 从它的三层循环可以看出,它的复杂度是n3,除了在第二层for中加点判断可以略微提高效率,几乎没有其他办法再减少它的复杂度。


四、练习

1、迪杰斯特拉(Dijkstra)算法练习:

①②③④⑤⑥⑦⑧

(①,②) 最短路径:4

(①,④) 最短路径:2

(①,④,③) 最短路径:3

(①,④,③,⑤) 最短路径:6

(①,④,③,⑦) 最短路径:6

(①,④,③,⑤,⑥) 最短路径:8

(①,④,③,⑤,⑧) 最短路径:18

2、佛洛依德(Floyed) 算法练习:

推导过程:

【数据结构】什么是图的最短路径?实现最短路径的2种算法?相关推荐

  1. 《数据结构与算法》(十四)- 图的应用:最短路径

    目录 前言 1. 最短路径 1.1 迪杰斯特拉(Dijkstra)算法 1.2 佛洛依德(Floyd)算法 2. 总结 原文地址:https://program-park.github.io/2021 ...

  2. 【2023王道数据结构】【图】通过C++实现图的BFS(广度优先遍历)算法求单源最短路径问题C、C++完整实现(可直接运行)

    ~~~笔锋至此又怎能平淡而终,故事开始便不承认普通✌✌✌ ✌ 题目及题解持续更新中 [2023王道数据结构目录]课后算法设计题C.C++代码实现完整版大全 题目: 通过C++实现图的BFS(广度优先遍 ...

  3. 大话数据结构 第七章 图(二) 最小生成树、最短路径、拓扑排序、关键路径算法

    大话数据结构 第七章 图(二) 最小生成树.最短路径.拓扑排序.关键路径算法 最小生成树 定义 Prim算法 Kruskal算法 最短路径 Dijkstra算法 Floyd算法 拓扑排序 AOV网 拓 ...

  4. 数据结构之图的应用:最短路径(Dijkstra、Floyd)

    图的应用:最短路径 思维导图: 最短路径的定义: BFS算法:(无权单源最短路径) Dijkstra算法:(无权单源.带权单源) Dijkstra算法原理: 算法实现中的辅助数组: 例: 如何通过pa ...

  5. 数据结构与算法(7-4)最短路径(迪杰斯特拉(Dijkstra)算法、弗洛伊德(Floyd)算法)

    目录 一.最短路径概念 二.迪杰斯特拉(Dijkstra)算法(单源最短路径) 1.原理 2.过程 3.代码 三.弗洛伊德(Floyd)算法(多源最短路径) 1.原理 2.存储 3.遍历 4.代码 参 ...

  6. 图的单源最短路径(Dijkstra算法)

    单源最短路径问题 如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径各边上的权值总和达到最小. Dijkstra算法由来 迪杰斯特拉算法(Dijkstra) ...

  7. Qt图形化界面—迷宫最短路径问题

    这段时间为了日后的工作需要,遵循霍亚飞老师的<Qt Creator快速入门(第三版)>学了第一大章基础篇的知识,并根据所学的知识尝试性地将之前的迷宫最短路径问题进行了图形化界面的设计.由于 ...

  8. 无权图的单源最短路径

    就像日常生活中的搭地铁问题,有的人会选择到达目的地最短距离的路线,有的人会选择地铁换乘次数最少的路线,其目的都是为了尽快到达目的地.选择到达目的地距离最短的路线,可以把两结点边的权值看成距离,而选择换 ...

  9. 图的应用---最短路径问题 用迪杰斯特拉算法解决 《地铁换乘问题》

    图的应用-最短路径问题 用迪杰斯特拉算法解决 <地铁换乘问题> 代码是在我学习的过程中完成的,也许会有问题,希望大家批评指正. 题目: 描述:已知2条地铁线路,其中A为环线,B为东西向线路 ...

最新文章

  1. 通过反射获取子类和父类定义的属性
  2. iOS swift lazy loading
  3. vsftpd.conf详解
  4. 蓝牙mesh — 解密蓝牙mesh系列文章汇总
  5. 趣链 BitXHub跨链平台 (1)技术架构
  6. 超越谷歌BERT!依图推出预训练语言理解模型ConvBERT
  7. 配置MySQL8.0 环境变量
  8. android怎样判断插入数据是否成功_MySQL一个表的自增id用完了,背井大佬让我用这些姿势再往里插数据...
  9. 点击率预估与冷启动(二)
  10. osm数据下载 python_用Python解锁处理OSM数据的全部姿势
  11. 【java】计算 list 中每一行的合计值
  12. 组策略最佳实践之“降龙十八掌”
  13. 2006吴山庙会-怎么都是人啊?
  14. 不加载任何包,手撕一个R语言版BP神经网络模型
  15. html 判断为空js,JavaScript判断DIV内容是否为空的方法
  16. WPE教程 传奇神秘商店外挂制作
  17. 淘宝天猫返利查券机器人搭建
  18. git 拉取远端分支
  19. c语言字符就地逆置,高手看看我的C语言代码单链表实现就地逆置
  20. w ndows默认截图工具,浅谈Win10系统下截屏方式

热门文章

  1. CSS 魔法 | 超强的文本超出提示效果
  2. 【Js】【调试】VSCode中调试Js代码
  3. qrcode生成,二维码生成
  4. PPK 无人机空间定位的秘密武器
  5. ctf各种sql盲注脚本
  6. 使用Struts的论坛系统的设计与实现
  7. linux 目录最大文件数,Linux目录数和文件数限制(目录上最大文件数)
  8. xp系统查不到共享计算机名,xp系统查找不到网络打印机怎么办?xp系统找不到网络打印机的三种解决方法图文教程...
  9. logo免费制作分享
  10. JavaScript-0.5时四舍五入