Dijkstra迪杰斯特拉算法



每个顶点之间的边都带着1个权值,这个权值可以表示任意的花费,距离,时间等等。
比如说我们指定一个起始的顶点A,和一个末尾的顶点E, 如果我们要求这2个单元之间的最短路径,
实际上,它把A-B,A-C,A-D,A-E,A-F的最短路径都算出来了,最后才得到A-E的最短路径是什么
通过迪杰斯特拉算法,我们可以知道从起始节点开始,到任意一个节点的最短路径。

处理过程


迪杰斯特拉算法首先给了我们2个集合:S集合和U集合
迪杰斯特拉算法的核心思想:计算了起始节点到其他所有节点的最短路径。
它不计算起始节点到所有节点的最短路径,可能就不知道A-E选择哪条路径是最短的。
S集合:存放已求出最短路径的顶点集合
U集合:存放未确定最短路径的顶点的集合

比如说,A-B,B是A的出边,A可以到达B,距离是6,权值是6
A-D,A不能直接到达D,所以A-D的权值就是无穷大

初始时,S集合只有一个源点,我们当做是A节点,我们以A为起始的顶点,A-A不用做任何的花费,相当于就是已经知道A如何到达A了
此时,U集合存放的就是:BCDEF

当然,我们还有一个辅助的数组,记录所有节点的当前计算出的最短路径信息

因为它在一步一步计算
比如说A-B是6
A-C-B是5
也就是说A-C-B的权值更小
算法要求图中不存在负权边
如果存在负权,就代表了其他的意义,成了减法,无法正确表达迪杰斯特拉算法的思想
迪杰斯特拉算法就是通过权值的和最小来计算最短路径的
所以,权值都是正数
辅助数组的初始化长度:有几个顶点就是多长

A-A我们记成INF,也叫做无穷大,A-B是6,A-C是3,A-D是INF,A-E是INF,A-F是INF
这就表示S集合中的A,已经是计算出来A到所有节点的路径了
S集合的初始化是A,然后我们在辅助数组也初始化了A到所有节点的路径

这个是初始化操作
现在,循环5次,计算A到BCDEF

首先在遍历U集合,找出当前S集合中的A,到哪个节点的权值是最小的。
我们就遍历这个辅助数组就可以了,发现是3,对应的是C
现在就是找到U集合中权值的最小值,然后把C从U集合移动到S集合当中

我们的辅助数组记录的是A到其他节点的目前为止的最短路径信息。
现在又有一个C进来了。
现在就有2种可能:A走到C,一种是A直接走到其他所有节点,一种是:A-B的权值是6,说不定呢,把一个新的最小权值的顶点加到S集合当中,A-C-B的权值可能比A-B的权值小,也有可能A-B的权值大于A-C-B的权值
A-C-D的权值可能比原来A-D的权值更小。
也就是说。当我们把C加到S集合当中,还没有完事,需要更新一下辅助数组,现在有一个新的顶点进来S了,现在把U集合中的顶点的权值再计算一下,U集合是之前认为的暂时的最短路径,现在有C进来了,要更新一下了。
现在U集合:BDEF
所以我们在辅助数组中更新这几个元素
我们看B,A-C是3,C-B是2,3+2=5,这个5比原来A直接到B的6小!
所以说A-C-B的这个路径是更短的。
所以,我们把原来的6改为5

然后我们看D,A-C是3,C-D是3,3+3=6,A-C-D是6
而原来的A-D是INF无穷大,6更短,所以这个INF就被替换为6了

然后我们看E,原来的A-E是INF无穷大,A-C是3,C-E是4,3+4=7,很明显,7更小,所以我们把INF替换为7

然后我们看F,原来的A-F是INF无穷大,现在A-C是3,C-F也是INF无穷大,所以我们不管,不用更新了。

这一步就是辅助数组记录起始节点到所有节点的权值的初始化,然后第一次在U集合找出A到哪个节点的权值最小,然后把C移到S集合中,更新了一下辅助数组。
然后再接着就是重复刚才的步骤了,从U集合取出当前权值最小的节点,B=5是最小的,然后把B从U集合拿到S集合。

当前辅助数组记录的是A到其他所有节点或者A-C到其他所有节点的当前的最小路径权值
然后现在我们要更新一下辅助数组。
因为A-C-B到其他的节点的花费可能更小
我们看D
现在A-B是5,B-D是5,5+5=10,10小于D现有的6,就不更新了。
然后我们看E,A-C-B是5,B-E是INF无穷大,不更新了
然后我们看F,B-F也是INF无穷大,不更新了
现在就处理完了

现在D是U集合中权值最小的,把D从U集合移动到S集合中。然后更新一下辅助数组。
现在U集合中就剩下E和F了
我看E,A-D是6,D-E是2,6+2=8,8大于E现有的7,就不更新了。
然后我们看F,A-D是6,D-F是3,6+3=9,9小于无穷大,更新一下。

处理完成。
然后从U集合找出权值最小的,是E,我们把E从U集合移动到S集合中。
现在U集合就剩下F了
我们还要更新一下辅助数组
A-E是7,我们看F,E-F是5
7+5=12,12大于F现有的9,不更新
现在处理完了
然后U集合就剩下一个F了,把F从U集合移动到S集合中,OK了

现在A到其他所有节点的最短路径的权值已经计算好了。
但是最短路径信息还没有记录。
路径记录,记录每一个节点的前驱节点。
时间复杂度是O(n^2)

Dijkstra迪杰斯特拉算法代码实现

package com.fixbug;import java.util.Arrays;/*** 描述: 迪杰斯特拉算法实现** @Author shilei* @Date 2019/10/24*/
public class Dijkstra {/*** 实现一个基于邻接矩阵的带权图最短路径* @param start* @param end*/public void shortestPath(int start, int end){//顶点的个数final int N = 6;//表示节点之间无法到达final int INF = 100;//定义邻接矩阵------二维数组 int[][] graph = new int[][]{{INF, 6, 3, INF, INF, INF},{6, INF, 2, 5, INF, INF},{3, 2, INF, 3, 4, INF},{INF, 5, 3, INF, 2, 3},{INF, INF, 4, 2, INF, 5},{INF, INF, INF, 3, 5, INF}};//初始化A到其他所有节点的路径权值 //辅助数组,存储start到其它节点的权值int[] cost = new int[N];//用来表示节点是否已经计算好最短路径,用来区分S集合和U集合boolean[] use = new boolean[N];//用来记录节点的前驱节点int[] path = new int[N];//初始化操作use[start] = true;//把start节点放入S集合当中for (int i = 0; i < N; i++) {cost[i] = graph[start][i];//初始化辅助数组 //更新path数组if(cost[i] < INF){path[i] = start;//当前节点的前驱是start }}//迪杰斯特拉算法的时间复杂度是O(n^2)//开始迪杰斯特拉算法,计算start节点到U集合所有节点的最短路径for(int i=1; i < N; ++i){//从U集合当中,找权值最小的节点int k = -1;int min = INF;for (int j = 0; j < N; j++) {if(!use[j] && cost[j] < min){min = cost[j];k = j;}}//U集合中剩下的顶点都是无法到达的if(k == -1){break;}//把k节点从U集合放入S集合当中use[k] = true;//更新权值数组 min是start节点到k节点的最短路径for (int j = 0; j < N; j++) {if(!use[j] && min + graph[k][j] < cost[j]){//graph[k][j] 从K到j min是start到K cost[j] = min + graph[k][j];//这里表示从start走到k,从k再到j,其权值更小,路径更短path[j] = k; }}}System.out.println("最短路径是:" + cost[end]);//打印从start是怎么走到end的char[] datas = new char[]{'A', 'B', 'C', 'D', 'E', 'F'};System.out.print(datas[end] + " <- ");for(;;){end = path[end];System.out.print(datas[end] + " <- ");if(end == start){break;}}
#include <iostream>
#include <vector>
#include <queue>
using namespace std;#if 0
using uint = unsigned int;
const uint INF = INT_MAX;#if 0
// 迪杰斯特拉算法接口
int Dijkstra(vector<vector<uint>>& graph,int start,  // 起点 int end)    // 终点
{const int N = graph.size();// 存储各个顶点的最短路径(最小权值)vector<uint> dis(N, 0);vector<bool> use(N, false);// 把start放入S集合use[start] = true;// 初始化start到其它U集合顶点权值for (int i = 0; i < N; i++){dis[i] = graph[start][i];}// 把U集合中的顶点处理完  for (int i = 1; i < N; i++)    // O(n){// 先从U集合中找到权值最小的顶点   int k = -1;int min = INF;for (int j = 0; j < N; j++)  // O(n){if (!use[j] && min > dis[j]) // U集合的顶点{min = dis[j];k = j;}}if (k == -1){break;}// 把选出的顶点加入到S集合中use[k] = true;// 把U集合中剩余顶点的权值信息更新一下for (int j = 0; j < N; j++){if (!use[j] && min + graph[k][j] < dis[j]) // U集合{dis[j] = min + graph[k][j];}}}// 测试打印for (int d : dis){cout << d << " ";}cout << endl;return dis[end];
}
#endif// 迪杰斯特拉算法接口-优化
int Dijkstra(vector<vector<uint>>& graph,int start,  // 起点 int end)    // 终点
{const int N = graph.size();// 存储各个顶点的最短路径(最小权值)vector<uint> dis(N, 0);vector<bool> use(N, false);// 定义小根堆priority_queue<pair<uint, int>, vector<pair<uint, int>>, greater<pair<uint, int>>> que;// 把start放入S集合use[start] = true;// 初始化start到其它U集合顶点权值for (int i = 0; i < N; i++){dis[i] = graph[start][i];// 把除start顶点的其它顶点全部放入U集合小根堆中if (i != start){que.emplace(graph[start][i], i);}}// 把U集合中的顶点处理完  while (!que.empty())    // O(n){// 用小根堆找权值最小的顶点    O(logn)   pair<权值,顶点编号>// 先从U集合中找到权值最小的顶点   auto pair = que.top();que.pop();if (pair.first == INF){break;}int k = pair.second;int min = pair.first;if (use[k])  continue;// 把选出的顶点加入到S集合中use[k] = true;// 把U集合中剩余顶点的权值信息更新一下for (int j = 0; j < N; j++){if (!use[j] && min + graph[k][j] < dis[j]) // U集合{dis[j] = min + graph[k][j];// 更新U集合中顶点的权值!que.emplace(dis[j], j);}}}// 测试打印for (int d : dis){cout << d << " ";}cout << endl;return dis[end];
}int main()
{vector<vector<uint>> graph ={{0, 6, 3, INF, INF, INF},{6, 0, 2, 5, INF, INF},{3, 2, 0, 3, 4, INF},{INF, 5, 3, 0, 2, 3},{INF, INF, 4, 2, 0, 5},{INF, INF, INF, 3, 5, 0},};int distance = Dijkstra(graph, 0, 1);if (distance == INF){cout << "不存在有效路径!" << endl;}else{cout << "distance:" << distance << endl;}
}
#endif        System.out.println();}public static void main(String[] args) {Dijkstra dkstra = new Dijkstra();dkstra.shortestPath(0, 5);}
}

C++

#include <iostream>
#include <vector>
#include <queue>
using namespace std;#if 0
using uint = unsigned int;
const uint INF = INT_MAX;#if 0
// 迪杰斯特拉算法接口
int Dijkstra(vector<vector<uint>>& graph,int start,  // 起点 int end)    // 终点
{const int N = graph.size();// 存储各个顶点的最短路径(最小权值)vector<uint> dis(N, 0);vector<bool> use(N, false);// 把start放入S集合use[start] = true;// 初始化start到其它U集合顶点权值for (int i = 0; i < N; i++){dis[i] = graph[start][i];}// 把U集合中的顶点处理完  for (int i = 1; i < N; i++)    // O(n){// 先从U集合中找到权值最小的顶点   int k = -1;int min = INF;for (int j = 0; j < N; j++)  // O(n){if (!use[j] && min > dis[j]) // U集合的顶点{min = dis[j];k = j;}}if (k == -1){break;}// 把选出的顶点加入到S集合中use[k] = true;// 把U集合中剩余顶点的权值信息更新一下for (int j = 0; j < N; j++){if (!use[j] && min + graph[k][j] < dis[j]) // U集合{dis[j] = min + graph[k][j];}}}// 测试打印for (int d : dis){cout << d << " ";}cout << endl;return dis[end];
}
#endif// 迪杰斯特拉算法接口-优化
int Dijkstra(vector<vector<uint>>& graph,int start,  // 起点 int end)    // 终点
{const int N = graph.size();// 存储各个顶点的最短路径(最小权值)vector<uint> dis(N, 0);vector<bool> use(N, false);// 定义小根堆priority_queue<pair<uint, int>, vector<pair<uint, int>>, greater<pair<uint, int>>> que;// 把start放入S集合use[start] = true;// 初始化start到其它U集合顶点权值for (int i = 0; i < N; i++){dis[i] = graph[start][i];// 把除start顶点的其它顶点全部放入U集合小根堆中if (i != start){que.emplace(graph[start][i], i);}}// 把U集合中的顶点处理完  while (!que.empty())    // O(n){// 用小根堆找权值最小的顶点    O(logn)   pair<权值,顶点编号>// 先从U集合中找到权值最小的顶点   auto pair = que.top();que.pop();if (pair.first == INF){break;}int k = pair.second;int min = pair.first;if (use[k])  continue;// 把选出的顶点加入到S集合中use[k] = true;// 把U集合中剩余顶点的权值信息更新一下for (int j = 0; j < N; j++){if (!use[j] && min + graph[k][j] < dis[j]) // U集合{dis[j] = min + graph[k][j];// 更新U集合中顶点的权值!que.emplace(dis[j], j);}}}// 测试打印for (int d : dis){cout << d << " ";}cout << endl;return dis[end];
}int main()
{vector<vector<uint>> graph ={{0, 6, 3, INF, INF, INF},{6, 0, 2, 5, INF, INF},{3, 2, 0, 3, 4, INF},{INF, 5, 3, 0, 2, 3},{INF, INF, 4, 2, 0, 5},{INF, INF, INF, 3, 5, 0},};int distance = Dijkstra(graph, 0, 1);if (distance == INF){cout << "不存在有效路径!" << endl;}else{cout << "distance:" << distance << endl;}
}
#endif

643-Dijkstra迪杰斯特拉算法相关推荐

  1. JavaScript实现dijkstra迪杰斯特拉算法(附完整源码)

    JavaScript实现dijkstra迪杰斯特拉算法 PriorityQueue完整源代码 MinHeap.js完整源代码 Heap.js完整源代码 Comparator.js完整源代码 dijks ...

  2. C++实现Dijkstra(迪杰斯特拉)算法(附完整源码)

    C++Dijkstra迪杰斯特拉算法的实现 C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main函数测试) C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main ...

  3. Dijkstra迪杰斯特拉算法 C++实现

    本篇文章主要介绍了Dijkstra迪杰斯特拉算法的C++实现,文章包含两个部分,在第一部分中我会简单介绍迪杰斯特拉算法以及一些个人的理解,第二部分会对C++代码的逻辑进行解释.下面是我已经上传的代码资 ...

  4. Dijkstra(迪杰斯特拉)算法求单源最短路径问题

    Dijkstra(迪杰斯特拉)算法求单源最短路径问题 重要的事情说三遍:代码不是我写的!代码不是我写的!代码不是我写的! 第一个算法是严蔚敏数据结构(C语言版)上写的,第二个算法是王道数据结构上写的, ...

  5. 最短路径之Dijkstra(迪杰斯特拉)算法(无向图)

    简介      Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.由for循环可知,其时间 ...

  6. MATLAB轻松绘制地图路线——Dijkstra(迪杰斯特拉)算法最短路径规划

    文章目录 1. 地图绘制 2. 计算各节点之间的距离 3. Dijkstra(迪杰斯特拉)算法 4. 根据计算出的距离利用Dijkstra(迪杰斯特拉)算法找出指定节点之间的最短路径 工程文件(可直接 ...

  7. C语言实现Dijkstra(迪杰斯特拉)算法(附完整源码)

    Dijkstra迪杰斯特拉 Graph结构体定义 迪杰斯特拉算法完整源码(定义,实现,main函数测试) Graph结构体定义 struct Graph {int vertexNum;int **ed ...

  8. dijkstra迪杰斯特拉算法(邻接表法)

    算法简易过程: 迪杰斯特拉算法(朴素) O(n^2) G={V,E} V:点集合 E:边集合 初始化时 令 S={某源点ear}, T=V-S= {其余顶点},T中顶点对应的距离(ear, Vi)值若 ...

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

    一.简介 迪克斯特拉算法又名Dijkstra算法(属于贪心算法).Dijkstra算法是从一节点到其余各节点最短路径计算方法. 迪杰斯特拉算法以起始点为中心向外层层扩展,直到扩展到终点为止. 算法思想 ...

  10. 算法提升:图的Dijkstra(迪杰斯特拉)算法

    目录 概念 思路 代码 概念 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路 ...

最新文章

  1. Matlab:成功解决 Inner matrix dimension must agree
  2. spring中getBeansWithAnnotation(Class<? extends Annotation> annotationType)方法
  3. 五款常用邮件管理系统评测
  4. 微课|中学生可以这样学Python(1.3节):Python代码编写规范
  5. flask-uploads扩展的使用笔记
  6. 微软MSDN原版所有系统合集我告诉你,Windows历史操作系统索引
  7. nes模拟器java版_JAVA版手机FC/Nes模拟器vN
  8. 华景机器人百度_qq群机器人凉了,晨风创始人被抓,酷Q停止运营!
  9. 无线路由器怎么改密码
  10. lfs库下载_lua使用lfs.dll库进行文件操作
  11. 牛客网-C语言编程入门训练
  12. 定个理财小目标:8w到100w实盘
  13. Supplier和Vendor的区别
  14. Windows下nginx启动报错黑屏(1113: No mapping for the Unicode character exists in the target......
  15. 关于.9图失效以及.9图不可以错过的细节点
  16. 1546B AquaMoon and Stolen String
  17. 站长工具seo综合查询-批量查询域名扫描域名查询收录排名蜘蛛
  18. 用Excel从身份证号中提取出生日的两种方法
  19. 面经_西安葡萄城_软件开发实习生
  20. 六、数据备份软件的配置实验报告

热门文章

  1. python: 删除数组中重复元素
  2. Java回调(callback)机制
  3. 《CTO》第二期7月上市:不标准,毋宁死
  4. 【鱼眼相机模型】鱼眼相机投影模型理解
  5. iphone 键盘兼容_如何从iPhone键盘上删除表情符号按钮
  6. Windows10打开WiFi搜不到,飞行模式也不好用
  7. linux 创建目录 默认权限,如何设置UNIX/Linux中新创建目录或文件的默认权限
  8. 玩转你画我猜(一):程序实现自动绘图
  9. 程序员须知:面试中最容易被问到的18个算法题(附答案!)
  10. ES6常用数组去重,数组排序