c/c++ 图的最短路径 Dijkstra(迪杰斯特拉)算法

图的最短路径的概念:

一位旅客要从城市A到城市B,他希望选择一条途中中转次数最少的路线。假设途中每一站都需要换车,则这个问题反映到图上就是要找一条从顶点A到B所含边的数量最少的路径。我们只需从顶点A出发对图作广度优先遍历,一旦遇到顶点B就终止。由此所得广度优先生成树上,从根顶点A到顶点B的路径就是中转次数最少的路径。但是这只是一类最简单的图的最短路径问题。有时,对于旅客来说,可能更关心的是节省交通费用;而对于司机来说,里程和速度则是他们感兴趣的的信息。为了在图上表示相关信息,可对边赋以权值,权值可以表示两个城市之间的距离,或途中所需时间,或交通费用等等。此时路径长度的度量就不再是路径上边的数目,而是路径上边权值之和。

实现思路:

  • 创建2个辅助int*数组dist path,1个bool数组s
  • dist 存放目标顶点到每个顶点的最短距离
  • path 存放目标顶点到每个顶点的路径
  • s 被查找过的顶点设置为true,否则为false

图为下图

1,假设目标顶点为A,先从A开始找到各个顶点的权值,

A B C D E
dist 0 10 无穷大 30 100
path -1 0 0 0 0
s true false false false false

path含义:比如path[1]=0,就代表从下标为0的顶点(A顶点)到B顶点

2,从dist里找到s为false的最小值,也就是dist[1]的值10,下标1说明是顶点B,再从B开始找到各个顶点的权值,更新dist和path,并设置B为true

A B C D E
dist 0 10 60 30 100
path -1 0 1 0 0
s true true false false false

3,从dist里找到s为false最小值,也就是dist[3]的值30,下标3说明是顶点D,再从D开始找到各个顶点的权值,更新dist和path,并设置D为true

A B C D E
dist 0 10 50 30 90
path -1 0 3 0 3
s true true false true false

4,从dist里找到s为false最小值,也就是dist[2]的值50,下标2说明是顶点C,再从C开始找到各个顶点的权值,更新dist和path,并设置C为true

A B C D E
dist 0 10 50 30 60
path -1 0 3 0 2
s true true true true false

5,从dist里找到s为false最小值,也就是dist[4]的值60,下标4说明是顶点E,再从E开始找到各个顶点的权值,更新dist和path,并设置E为true

A B C D E
dist 0 10 50 30 60
path -1 0 3 0 2
s true true true true true

下面两幅图可以帮助理解

dijkstra.h

  1. #ifndef __mixspantree__
  2. #define __mixspantree__
  3. #include <stdio.h>
  4. #include <malloc.h>
  5. #include <assert.h>
  6. #include <memory.h>
  7. #include <stdlib.h>
  8. #include <stdbool.h>
  9. #define Default_vertex_size 20
  10. #define T char//dai biao ding dian de lei xing
  11. #define E int
  12. #define MAX_COST 0x7FFFFFFF
  13. typedef struct GraphMtx{
  14. int MaxVertices;//zui da ding dian shu liang]
  15. int NumVertices;//shi ji ding dian shu liang
  16. int NumEdges;//bian de shu lian
  17. T* VerticesList;//ding dian list
  18. int** Edge;//bian de lian jie xin xi, bu shi 0 jiu shi 1
  19. }GraphMtx;
  20. //chu shi hua tu
  21. void init_graph(GraphMtx* gm);
  22. //打印二维数组
  23. void show_graph(GraphMtx* gm);
  24. //插入顶点
  25. void insert_vertex(GraphMtx* gm, T v);
  26. //添加顶点间的线
  27. void insert_edge(GraphMtx* gm, T v1, T v2, E cost);
  28. //最短路径
  29. void short_path(GraphMtx* g,T v,E* dist, int* path);
  30. #endif

dijkstra.c

  1. #include "dijkstra.h"
  2. void init_graph(GraphMtx* gm){
  3. gm->MaxVertices = Default_vertex_size;
  4. gm->NumEdges = gm->NumVertices = 0;
  5. //kai pi ding dian de nei cun kong jian
  6. gm->VerticesList = (T*)malloc(sizeof(T) * (gm->MaxVertices));
  7. assert(NULL != gm->VerticesList);
  8. //创建二维数组
  9. //让一个int的二级指针,指向一个有8个int一级指针的数组
  10. //开辟一个能存放gm->MaxVertices个int一级指针的内存空间
  11. gm->Edge = (int**)malloc(sizeof(int*) * (gm->MaxVertices));
  12. assert(NULL != gm->Edge);
  13. //开辟gm->MaxVertices组,能存放gm->MaxVertices个int的内存空间
  14. for(int i = 0; i < gm->MaxVertices; ++i){
  15. gm->Edge[i] = (int*)malloc(sizeof(int) * gm->MaxVertices);
  16. }
  17. //初始化二维数组
  18. //让每个顶点之间的边的关系都为不相连的
  19. for(int i = 0; i < gm->MaxVertices; ++i){
  20. for(int j = 0; j < gm->MaxVertices; ++j){
  21. if(i == j)
  22. gm->Edge[i][j] = 0;
  23. else
  24. gm->Edge[i][j] = MAX_COST;
  25. }
  26. }
  27. }
  28. //打印二维数组
  29. void show_graph(GraphMtx* gm){
  30. printf(" ");
  31. for(int i = 0; i < gm->NumVertices; ++i){
  32. printf("%3c ", gm->VerticesList[i]);
  33. }
  34. printf("\n");
  35. for(int i = 0; i < gm->NumVertices; ++i){
  36. //在行首,打印出顶点的名字
  37. printf("%c:", gm->VerticesList[i]);
  38. for(int j = 0; j < gm->NumVertices; ++j){
  39. if(gm->Edge[i][j] == MAX_COST){
  40. printf("%3c ", '*');
  41. }
  42. else{
  43. printf("%3d ", gm->Edge[i][j]);
  44. }
  45. }
  46. printf("\n");
  47. }
  48. printf("\n");
  49. }
  50. //插入顶点
  51. void insert_vertex(GraphMtx* gm, T v){
  52. //顶点空间已满,不能再插入顶点了
  53. if(gm->NumVertices >= gm->MaxVertices){
  54. return;
  55. }
  56. gm->VerticesList[gm->NumVertices++] = v;
  57. }
  58. int getVertexIndex(GraphMtx* gm, T v){
  59. for(int i = 0; i < gm->NumVertices; ++i){
  60. if(gm->VerticesList[i] == v)return i;
  61. }
  62. return -1;
  63. }
  64. //添加顶点间的线
  65. void insert_edge(GraphMtx* gm, T v1, T v2, E cost){
  66. if(v1 == v2)return;
  67. //查找2个顶点的下标
  68. int j = getVertexIndex(gm, v1);
  69. int k = getVertexIndex(gm, v2);
  70. //说明找到顶点了,并且点之间还没有线
  71. if(j != -1 && k != -1 ){
  72. //因为是有方向,所以更新1个值
  73. gm->Edge[j][k] = cost;
  74. //边数加一
  75. gm->NumEdges++;
  76. }
  77. }
  78. //取得2个顶点之间的权值
  79. E getWeight(GraphMtx* g, int v1, int v2){
  80. if(v1 == -1 || v2 == -1) return MAX_COST;
  81. return g->Edge[v1][v2];
  82. }
  83. //最短路径
  84. void short_path(GraphMtx* g,T v,E* dist, int* path){
  85. int n = g->NumVertices;
  86. bool* s = (bool*)malloc(sizeof(bool) * n);
  87. assert(NULL != s);
  88. int vi = getVertexIndex(g, v);
  89. for(int i = 0; i < n; ++i){
  90. //获得各个顶点与目标顶点之间的权值
  91. dist[i] = getWeight(g, vi, i);
  92. s[i] = false;
  93. if(i != vi && dist[i] < MAX_COST){
  94. path[i] = vi;
  95. }
  96. else{
  97. path[i] = -1;
  98. }
  99. }
  100. s[vi] = true;
  101. int min;
  102. int w;
  103. for(int i = 0; i < n - 1; ++i){
  104. min = MAX_COST;
  105. //u为最短路径顶点的下标
  106. int u = vi;
  107. for(int j = 0; j < n; ++j){
  108. if(!s[j] && dist[j] < min){
  109. u = j;
  110. min = dist[j];
  111. }
  112. }
  113. //把u加入到s集合
  114. s[u] = true;
  115. //更新下一个点到所有点的权值
  116. for(int k = 0; k < n; ++k){
  117. w = getWeight(g, u, k);
  118. if(!s[k] && w < MAX_COST && dist[u] + w < dist[k]){
  119. dist[k] = dist[u] + w;
  120. path[k] = u;
  121. }
  122. }
  123. }
  124. }

dijkstramain.c

  1. #include "dijkstra.h"
  2. int main(){
  3. GraphMtx gm;
  4. //初始化图
  5. init_graph(&gm);
  6. //插入顶点
  7. insert_vertex(&gm, 'A');
  8. insert_vertex(&gm, 'B');
  9. insert_vertex(&gm, 'C');
  10. insert_vertex(&gm, 'D');
  11. insert_vertex(&gm, 'E');
  12. //添加连线
  13. insert_edge(&gm, 'A', 'B', 10);
  14. insert_edge(&gm, 'A', 'D', 30);
  15. insert_edge(&gm, 'A', 'E', 100);
  16. insert_edge(&gm, 'B', 'C', 50);
  17. insert_edge(&gm, 'C', 'E', 10);
  18. insert_edge(&gm, 'D', 'C', 20);
  19. insert_edge(&gm, 'D', 'E', 60);
  20. //打印图
  21. show_graph(&gm);
  22. int n = gm.NumVertices;
  23. E* dist = (E*)malloc(sizeof(E) * n);
  24. int* path = (int*)malloc(sizeof(int) * n);
  25. assert(NULL != dist && NULL != path);
  26. //最短路径
  27. short_path(&gm, 'A', dist, path);
  28. }

完整代码

编译方法:gcc -g dijkstra.c dijkstramain.c

执行结果如下图:

c/c++ 图的最短路径 Dijkstra(迪杰斯特拉)算法的更多相关文章

  1. 图解Dijkstra(迪杰斯特拉)算法+代码实现

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

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

    迪杰斯特拉算法是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 算法思想:设G=(V,E)是一个带权有向图 ...

  3. 最短路径之迪杰斯特拉算法的Java实现

    Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备 ...

  4. 最短路径之迪杰斯特拉算法(Java)

    1)Dijkstra算法适用于求图中两节点之间最短路径 2)Dijkstra算法设计比较巧妙的是:在求源节点到终结点自底向上的过程中,源节点到某一节点之间最短路径的确定上(这也是我之前苦于没有解决的地 ...

  5. Dijkstra(迪杰斯特拉)算法求解最短路径

    过程 首先需要记录每个点到原点的距离,这个距离会在每一轮遍历的过程中刷新.每一个节点到原点的最短路径是其上一个节点(前驱节点)到原点的最短路径加上前驱节点到该节点的距离.以这个原则,经过N轮计算就能得 ...

  6. js图的数据结构处理---迪杰斯特拉算法

    /*//1.确定数据结构, mapf[i][j] 为点i到点j的距离 [ Infinity 2 5 Infinity Infinity Infinity Infinity 2 6 Infinity I ...

  7. 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)

    文字描述 引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息.上面这些问题,都可以转化为求图中,两 ...

  8. 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)

    Dijkstra算法 ———————————最后更新时间:2011.9.25———————————Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径. ...

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

    什么也不想说,现在直接上封装的方法: using System; using System.Collections.Concurrent; using System.Collections.Gener ...

随机推荐

  1. Nacos发布0.5.0版本,轻松玩转动态 DNS 服务

    阿里巴巴微服务开源项目Nacos于近期发布v0.5.0版本,该版本主要包括了DNS-basedService Discovery,对Java 11的支持,持续优化Nacos产品用户体验,更深度的与Sp ...

  2. Oracle数据库over函数的使用

    转自:  https://blog.csdn.net/a1065423444/article/details/75635611 over()函数写法over(partition by expr2 or ...

  3. linux 两个查找工具 locate,find

    linux 中有很多查找工具,今天主要讲解locate,find两个工具. 一.locate 1.性能介绍 查询系统上预建的文件索引数据库 /var/lib/mlocate/mlocate.db 注意 ...

  4. Go Web:数据存储(2)——CSV文件

    存储到CSV文件中 1.内存存储 2.CSV文件存储 3.gob序列化存储 本文接上一篇:内存存储. 关于CSV文件的说明,见csv文件格式 当数据存储到了内存中,可以在需要的时候持久化保存到磁盘文件 ...

  5. OJ:析构函数实现多态

    Description 下面程序的输出结果是: destructor B destructor A 请完整写出 class A. 限制条件:不得为 class A 编写构造函数. #include & ...

  6. tiny210 tslib 测试(基于 ft5x06 触摸屏),解决触摸无效问题

    1. 拷贝至开发板 将上次实验中的 tmp 文件夹拷贝到开发板,可以通过 nfs 来传输,并将 tmp/lib 下的所有 .so 文件拷贝至 开发板的 /usr/lib 中,并且确保库的映射关系正确. ...

  7. SELECT INTO和INSERT INTO SELECT的区别

    数据库中的数据复制备份 SELECT INTO: 形式: SELECT value1,value2,value3 INTO Table_2 FROM Table_1 Table_2表存在,报错:数据库 ...

  8. C#泛型。

    作用: 使用泛型可以实现算法重用. class Program { static void Main(string[] args) { MyClass<string> myClass = ...

  9. ASP.NET MVC 学习笔记-6.异步控制器

    1)         异步控制器的由来 对于IIS,它维护了一个.NET线程池来处理客户端请求,这个线程池称为工作线程池,其中的线程称为工作线程.当IIS接收到一个请求时,需要从工作线程池中唤醒一个工 ...

  10. spring boot 打jar包,获取resource路径下的文件

    前言:最近在spring boot项目静态类中获取resource路径下文件,在idea中启动都可以获取,但是打包后变成了jar包 就无法获取到. 我想到了两种方法,一种是根据http访问静态资源比如 ...