一、算法介绍

  迪杰斯特拉算法(英语:Dijkstra's algorithm)由荷兰计算机科学家艾兹赫尔·迪杰斯特拉在1956年提出。迪杰斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题。这个算法是通过为每个顶点 v 保留当前为止所找到的从s到v的最短路径来工作的。

  初始时,原点 src 的路径权重被赋为 0 (dist[src] = 0)。若对于顶点 m 存在能直接到达的边(src, m),则把d[m]设为w(src, m),同时把所有其他(src不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于所有顶点的集合 V 中的任意顶点 v, 若 v 不为 src 和上述 m 之一, dist[v] = ∞)。当算法结束时,dist[v] 中存储的便是从 src 到 v 的最短路径,或者如果路径不存在的话是无穷大。

  边的拓展是 Dijkstra 算法的基础操作:如果存在一条从 u 到 v 的边,那么从 src 到 v 的最短路径可以通过将边(uv)添加到从 src 到 u 的路径尾部来拓展一条从 src 到 v 的路径。这条路径的长度是 dist[u] + w(u, v)。如果这个值比当前已知的 dist[v] 的值要小,我们可以用新的最小值来替代当前 dist[v] 中的值。拓展边的操作一直运行到所有的 dist[v] 都代表从 src 到 v 的最短路径的长度值。此算法的组织令 dist[u] 达到其最终值时,每条边(uv)都只被拓展一次。

二、Dijkstra算法步骤

  以下是 Dijkstra 算法中用于查找从单个源顶点到给定图中所有其他顶点的最短路径的详细步骤。

  1)创建一个集合sptSet(最短路径树集合),该集合跟踪最短路径树中包含的顶点,即,其与源点的最小距离已被计算并确定。最初,此集合为空。

  2)将距离值分配给输入图中的所有顶点。将所有距离值初始化为无穷大。将源顶点的距离值指定为0(dist[src] = 0),以便首先选择它。

  3)虽然当前的 sptSet (表示最短路径树)并不包含所有顶点:

  • 选择一个顶点 u,该顶点在 sptSet 中不存在,并且具有最小距离值。

  • 将u包含到 sptSet 中。

  • 更新u的所有相邻顶点的距离值。要更新距离值,要遍历所有相邻的顶点。对于每个相邻顶点 v,如果u(来自源点)的距离值和边缘u-v的权重之和小于v的距离值(dist[u] + graph[u][v] < dist[v]),则更新v的距离值。

  下面来看一个例子:

  集合 sptSet[] 最初为空,并且分配给每个顶点的距离为 dist[] = {0,INF,INF,INF,INF,INF,INF,INF},其中INF表示无穷大。 现在选择具有最小距离值的顶点。 选择顶点0,将其包含在 sptSet 中。 因此,sptSet 变为 {0}。 将 0 包含到 sptSet 之后,更新其相邻顶点的距离值。 0 的相邻顶点是 1 和 7。1 和 7 的距离值被更新为 4 和 8。下面的子图显示了顶点及其距离值,仅显示了具有有限距离值的顶点。 最短路径树中包含的顶点显示为绿色。

  选择具有最小距离值且尚未包含在最短路径树中的顶点(不在 sptSet 中)。 选择 顶点1 并将其添加到 sptSet。 因此,sptSet 现在变为 {0,1}。 更新相邻顶点的距离值1。顶点2 的距离值变为 12。

  选择具有最小距离值且尚未包含在最短路径树中的顶点(不在 sptSet 中)。 选择了顶点7。 因此,sptSet 现在变为 {0,1,7}。 更新相邻 顶点7 的距离值。顶点 6 和 8 的距离值变得有限(分别为 15 和 9)。

  选择具有最小距离值且尚未包含在最短路径树中的顶点(不在 sptSet 中)。选择了顶点6。因此,sptSet现在变为 {0,1,7,6}。更新相邻 顶点6 的距离值。更新顶点 5 和 8 的距离值。

  重复上述步骤,直到 sptSet 确实包含给定图的所有顶点。最后,我们得到以下最短路径树:

三、实现代码

  下面是使用了邻接矩阵的迪杰斯特拉算法实现。其算法的时间复杂度为 O(V2)。

  1. 1 /**
  2. 2 * 为使用邻接矩阵表示的图实现Dijkstra的单源最短路径算法的函数
  3. 3 *
  4. 4 * @param graph 地图,给出的邻接矩阵
  5. 5 * @param src 源顶点
  6. 6 */
  7. 7 public void dijkstra(int[][] graph, int src) {
  8. 8 /* 输出数组,dist[i]将保存从src到i的最短距离 */
  9. 9 int[] dist = new int[V];
  10. 10
  11. 11 /* 如果顶点i包含在最短路径树中或从src到i的最短距离已确定,则sptSet[i]将为true */
  12. 12 Boolean[] sptSet = new Boolean[V];
  13. 13
  14. 14 /* 将所有距离初始化为无穷大并将stpSet[]初始化为false */
  15. 15 for (int i = 0; i < V; i++) {
  16. 16 dist[i] = Integer.MAX_VALUE;
  17. 17 sptSet[i] = false;
  18. 18 }
  19. 19
  20. 20 /* 源顶点与其自身的距离始终为0 */
  21. 21 dist[src] = 0;
  22. 22
  23. 23 /* 查找所有顶点的最短路径 */
  24. 24 for (int count = 0; count < V - 1; count++) {
  25. 25 int u = minDistance(dist, sptSet);
  26. 26
  27. 27 /* 将选取的顶点标记为已处理 */
  28. 28 sptSet[u] = true;
  29. 29
  30. 30 /* 更新选取的顶点的相邻顶点的dist值。*/
  31. 31 for (int v = 0; v < V; v++) {
  32. 32 /* 仅当不在sptSet中标记过且在u到v之间存在边且从src到通过u的v的路径的总权重小于dist[v]的当前值时,
  33. 33 才更新dist [v]。*/
  34. 34 if (!sptSet[v] && graph[u][v] != 0 && dist[u] != Integer.MAX_VALUE && dist[u] + graph[u][v] < dist[v]) {
  35. 35 dist[v] = dist[u] + graph[u][v];
  36. 36 }
  37. 37 }
  38. 38 }
  39. 39
  40. 40 /* 打印构造的最短距离数组 */
  41. 41 printSolution(dist);
  42. 42 }

  函数 minDistance(),从尚未包含在最短路径树中的一组顶点中查找具有最小距离值的顶点,就是算法从已知的最短路径树外选取距离远点比较近的顶点来进行边的扩展。此函数的时间复杂度为 O(V)。

  1. 1 /**
  2. 2 * 从尚未包含在最短路径树中的一组顶点中查找具有最小距离值的顶点
  3. 3 *
  4. 4 * @param dist 存当前距离源点的最短路径
  5. 5 * @param sptSet 顶点是否存在于最短路树中
  6. 6 * @return
  7. 7 */
  8. 8 public int minDistance(int[] dist, Boolean[] sptSet) {
  9. 9 /* 初始化最小值 */
  10. 10 int min = Integer.MAX_VALUE;
  11. 11 int min_index = -1;
  12. 12
  13. 13 for (int v = 0; v < V; v++) {
  14. 14 if (!sptSet[v] && dist[v] <= min) {
  15. 15 min = dist[v];
  16. 16 min_index = v;
  17. 17 }
  18. 18 }
  19. 19
  20. 20 return min_index;
  21. 21 }

单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(一)的更多相关文章

  1. [C++]单源最短路径:迪杰斯特拉(Dijkstra)算法(贪心算法)

    1 Dijkstra算法 1.1 算法基本信息 解决问题/提出背景 单源最短路径(在带权有向图中,求从某顶点到其余各顶点的最短路径) 算法思想 贪心算法 按路径长度递增的次序,依次产生最短路径的算法 ...

  2. JS实现最短路径之迪杰斯特拉(Dijkstra)算法

    最短路径: 对于网图来说,最短路径是指两个顶点之间经过的边上权值和最少的路径,我们称第一个顶点是源点,最后一个顶点是终点 迪杰斯特拉 ( Dijkstra) 算法是并不是一下子就求出 了 Vo 到V8 ...

  3. 最短路径算法-迪杰斯特拉(Dijkstra)算法在c#中的实现和生产应用

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止 贪心算法(Greedy ...

  4. 迪杰斯特拉Dijkstra算法介绍

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijk ...

  5. 最短路径-迪杰斯特拉(dijkstra)算法及优化详解

    简介: dijkstra算法解决图论中源点到任意一点的最短路径. 算法思想: 算法特点: dijkstra算法解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树.该算法常用于路由算 ...

  6. 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)

    一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...

  7. 图的最短路径---迪杰斯特拉(Dijkstra)算法浅析

    什么是最短路径 在网图和非网图中,最短路径的含义是不一样的.对于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径. 对于网图,最短路径就是指两顶点之间经过的边上权值之和最 ...

  8. 最短路径 - 迪杰斯特拉(Dijkstra)算法

    对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点为源点,最后一个顶点为终点.最短路径的算法主要有迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd ...

  9. C# 迪杰斯特拉(Dijkstra)算法

    Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 其基本思想是,设置顶点集合S并不断地作 ...

随机推荐

  1. ysoserial exploit/JRMPClient

    ysoserial exploit/JRMPClient 上一篇文章讲到,当服务器反序列化payloads/JRMPListener,即会开启端口监听.再使用exploit/JRMPClient模块发 ...

  2. 日期SQL 脚本

    一个月第一天的 SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)本周的星期一     SELECT DATEADD(wk, DATEDIFF(wk,0,g ...

  3. SQLSERVER存储过程基础

    SQLSERVER存储过程基础 1.声明变量 DECLARE     @F001  SMALLINT,  (三元素,声明declare+变量名+类型) @F002  INTEGER, @F003  V ...

  4. freeswitch刷新网关方法

    1.freeswitch xml配置文件新增网关后,使其生效,可以重启freeswitch或者使用命令方式 fs_cli -H 127.0.0.1 -P 8021 -p hmzj -x sofia p ...

  5. java中各个类相互调用资源的原理

       当我们要进行跨类的调用/使用的时候,比如当前类调用另一个类中的变量或方法时, 这时需要一定的条件,如果那些将要被调用的变量或方法是static(静态)变量,也叫类变 量,那么可以通过类名调用,相 ...

  6. 简单学习PHP中的层次性能分析器

    在 PHP 中,我们需要进行调试的时候,一般都会使用 memory_get_usage() 看下内存的使用情况.但如果想看当前的脚本 CPU 的占用情况就没有什么现成的函数了.不过,PHP 也为我们提 ...

  7. symfony2已有数据表导入实体时报错 Doctrine does not support reverse engineering from tables that don't have a primary key

    先在配置文件 app/config/config.yml中配置 schema_filter: /^(?!(tablename))/ 即可,或者在出现问题表都加上一个id 然后再使用命令 php app ...

  8. Docker系列(7)- 常用命令(3) | 容器命令

    容器命令 说明: 有了镜像才可以创建容器:下载一个centos镜像进行练习,相当于在Linux里面再见一个Linux虚拟机 [root@localhost ~]# docker pull centos ...

  9. 定要过python二级 第10套

    第一部分 第一题 1. int* 字符串 =几个东西 2. 此题的最开始的疑惑 (1)01 02 03  怎么产生  for 循环 (2)<<< 这个怎么产生 (3)<这个&l ...

  10. truncate表时报“唯一/主键被启用的外部关键字引用”解决办法

    前言:清空表时提示"唯一/主键被启用的外部关键字引用"这一警告信息 原因:是因为主键被子表引用,所以对主键进行更改就好了 解决: 使用 alter table table_name ...