写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站。博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事,做自己以后不会留有遗憾的事,做自己觉得有意义的事,不浪费这大好的青春年华。博主写博客目的是记录所学到的知识并方便自己复习,在记录知识的同时获得部分浏览量,得到更多人的认可,满足小小的成就感,同时在写博客的途中结交更多志同道合的朋友,让自己在技术的路上并不孤单。

目录:
1.求最短路径的两种算法简介
2.迪杰斯特拉(Dijkstra 算法)
        迪杰斯特拉算法简介
        迪杰斯特拉算法代码实现(C完整代码)
        迪杰斯特拉算法小结
3.弗洛伊德算法
        弗洛伊德算法简介
        迪杰斯特拉算法代码实现(C完整代码)
        弗洛伊德算法小结

1.求最短路径的两种算法简介

在一个网(有权图)中,求一个顶点到另一个顶点的最短路径的计算方式有两种:迪杰斯特拉(Dijkstra 算法)弗洛伊德(Floyd)算法迪杰斯特拉算法计算的是有向网中的某个顶点到其余所有顶点的最短路径;弗洛伊德算法计算的是任意两顶点之间的最短 路径最短路径算法既适用于有向网,也同样适用于无向网。本节将围绕有向网讲解迪杰斯特拉算法的具体实现

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

2.1迪杰斯特拉算法简介

迪杰斯特拉算法计算的是从网中一个顶点到其它顶点之间的最短路径问题


如图 所示是一个有向网,在计算 V0 到其它所有顶点之间的最小路径时,迪杰斯特拉算法的计算方式为:

从 V0 出发,由于可以直接到达 V2 、V3和 V5 ,而其它顶点和 V0 之间没有弧的存在,所以之间的距离设定为无穷大,可以得到 下面这个表格:

从表格中可以看到,V0 到 V2 的距离最近,所以迪杰斯特拉算法设定 V0-V2 为 V0 到 V2 之间的最短路径,最短路径的权 值和为 10

已经判断 V0-V2 是最短路径,所以以 V2 为起始点,判断 V2 到除了 V0 以外的其余各点之间的距离,如果对应的权值比前 一张表格中记录的数值小,就说明网中有一条更短的路径,直接更新表格;反之表格中的数据不变。可以得到下面这个表格:

例如,表格中 V0 到 V3 的距离,发现当通过 V2 到达 V3 的距离比之前的 ∞ 要小,所以更新表格。

更新之后,发现 V0-V4 的距离最近,设定 V0 到 V4 的最短路径的值为 30。之后从 V4 出发,判断到未确定最短路径的其 它顶点的距离,继续更新表格

更新后确定从 V0 到 V3 的最短路径为 V0-V4-V3,权值为 50。然后从 V3 出发,继续判断:

对于 V5 来说,通过 V0-V4-V3-V5 的路径要比之前的权值 90 还要小,所以更新表格,更新后可以看到,V0-V5 的距离此时 最短,可以确定 V0 到 V5 的最短路径为 60。

最后确定 V0-V1 的最短路径,由于从 V0 无法到达 V1 ,最终设定 V0 到 V1 的最短路径为 ∞(无穷大)。在确定了 V0 与其他所有顶点的最短路径后,迪杰斯特拉算法才算结束。

实际上无向网中的最短路径问题也可以使用迪杰斯特拉算法解决, 解决过程和上述过程完全一致。

2.2迪杰斯特拉算法代码实现(C完整代码)

#include <stdio.h>
#define MAX_VERtEX_NUM 20 //顶点的最大个数
#define VRType int //表示弧的权值的类型
#define VertexType int //图中顶点的数据类型
#define INFINITY 65535
typedef struct {VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据VRType arcs[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //二维数组,记录顶点之间的关系int vexnum,arcnum; //记录图的顶点数和弧(边)数
}MGraph;
typedef int PathMatrix[MAX_VERtEX_NUM]; //用于存储最短路径中经过的顶点的下标
typedef int ShortPathTable[MAX_VERtEX_NUM]; //用于存储各个最短路径的权值和
//根据顶点本身数据,判断出顶点在二维数组中的位置
int LocateVex(MGraph * G,VertexType v){int i=0;//遍历一维数组,找到变量 vfor (; i<G->vexnum; i++) {if (G->vexs[i]==v) {break;}}
//如果找不到,输出提示语句,返回-1
if (i>G->vexnum) {printf("no such vertex.\n"); return -1;}return i;
}
//构造有向网
void CreateUDG(MGraph *G){ scanf("%d,%d",&(G->vexnum),&(G->arcnum));for (int i=0; i<G->vexnum; i++) {scanf("%d",&(G->vexs[i]));}for (int i=0; i<G->vexnum; i++) {for (int j=0; j<G->vexnum; j++) {G->arcs[i][j]=INFINITY;}}
for (int i=0; i<G->arcnum; i++) {int v1,v2,w; scanf("%d,%d,%d",&v1,&v2,&w);int n=LocateVex(G, v1);int m=LocateVex(G, v2);if (m==-1 ||n==-1) {printf("no this vertex\n"); return;}G->arcs[n][m]=w;}
} //迪杰斯特拉算法,v0 表示有向网中起始点所在数组中的下标
void ShortestPath_Dijkstra(MGraph G,int v0,PathMatrix *p,ShortPathTable *D){int final[MAX_VERtEX_NUM];//用于存储各顶点是否已经确定最短路径的数组
//对各数组进行初始化for (int v=0; v<G.vexnum; v++) {final[v]=0;(*D)[v]=G.arcs[v0][v];(*p)[v]=0;
}
//由于以 v0 位下标的顶点为起始点,所以不用再判断(*D)[v0]=0;final[v0]=1;int k = 0;for (int i=0; i<G.vexnum; i++) {int min=INFINITY;
//选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点for (int w=0; w<G.vexnum; w++) {if (!final[w]) {if ((*D)[w]<min) {k=w; min=(*D)[w];}}
}
//设置该顶点的标志位为 1,避免下次重复判断final[k]=1;
//对 v0 到各顶点的权值进行更新for (int w=0; w<G.vexnum; w++) {if (!final[w]&&(min+G.arcs[k][w]<(*D)[w])) {(*D)[w]=min+G.arcs[k][w];(*p)[w]=k;//记录各个最短路径上存在的顶点}}}
}
int main(){MGraph G;CreateUDG(&G);PathMatrix P;ShortPathTable D;ShortestPath_Dijkstra(G, 0, &P, &D);for (int i=1; i<G.vexnum; i++) {printf("V%d - V%d 的最短路径中的顶点有(逆序):",0,i);printf(" V%d",i);int j=i;
//由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可得到各个最短路径上的所有顶点while (P[j]!=0) {printf(" V%d",P[j]);j=P[j];}printf(" V0\n");}printf("源点到各顶点的最短路径长度为:\n");for (int i=1; i<G.vexnum; i++) {printf("V%d - V%d : %d \n",G.vexs[0],G.vexs[i],D[i]);}return 0;
}

对于本例子:

输入
6,8
0
1
2
3
4
5
0,5,100
0,4,30
0,2,10
1,2,5
2,3,50
3,5,10
4,3,20
4,5,60
//输出
V0 - V1 的最短路径中的顶点有: V1 V0
V0 - V2 的最短路径中的顶点有: V2 V0
V0 - V3 的最短路径中的顶点有: V3 V4 V0
V0 - V4 的最短路径中的顶点有: V4 V0
V0 - V5 的最短路径中的顶点有: V5 V3 V4 V0
源点到各顶点的最短路径长度为:
V0 - V1 : 65535
V0 - V2 : 10
V0 - V3 : 50
V0 - V4 : 30
V0 - V5 :

2.3迪杰斯特拉算法小结

迪杰斯特拉算法解决的是从网中的一个顶点到所有其它顶点之间的最短路径,算法整体的时间复杂度为 O(n2)。但是如果需要求 任意两顶点之间的最短路径,使用迪杰斯特拉算法虽然最终虽然也能解决问题,但是大材小用,相比之下使用弗洛伊德算法解决 此类问题会更合适。

3.弗洛伊德算法

3.1弗洛伊德算法简介

弗洛伊德的核心思想是:对于网中的任意两个顶点(例如顶点 A 到顶点 B)来说,之间的最短路径不外乎有 2 种情况:

  1. 直接从顶点 A 到顶点 B 的弧的权值为顶点 A 到顶点 B 的最短路径;
  2. 从顶点 A 开始,经过若干个顶点,最终达到顶点 B,期间经过的弧的权值和为顶点 A 到顶点 B 的最短路径。

所以,弗洛伊德算法的核心为:对于从顶点 A 到顶点 B 的最短路径,拿出网中所有的顶点进行如下判断:

Dis(A,K)+ Dis(K,B)< Dis(A,B)

其中,K 表示网中所有的顶点;Dis(A,B) 表示顶点 A 到顶点 B 的距离。

也就是说,拿出所有的顶点 K,判断经过顶点 K 是否存在一条可行路径比直达的路径的权值小,如果式子成立,说明确实存在一条权值更小的路径,此时只需要更新记录的权值和即可。

任意的两个顶点全部做以上的判断,最终遍历完成后记录的最终的权值即为对应顶点之间的最短路径

如下图:

例如,在使用弗洛伊德算法计算上图中的任意两个顶点之间的最短路径时,具体实施步骤为: 首先,记录顶点之间初始的权值,如下表所示:

依次遍历所有的顶点,假设从 V0 开始,将 V0 作为中间点,看每对顶点之间的距离值是否会更小。最终 V0 对于每对顶点之 间的距离没有任何改善。

对于 V0 来说,由于该顶点只有出度,没有入度,所以没有作为中间点的可能。同理,V1 也没有可能。

将 V2 作为每对顶点的中间点,有影响的为 (V0,V3) 和 (V1,V3):
例如,(V0,V3)权值为无穷大,而(V0,V2)+(V2,V3)= 60,比之前的值小,相比而言后者的路径更短;同理 (V1, V3)也是如此。

更新的表格为:

以 V3 作为中间顶点遍历各队顶点,更新后的表格为:

以 V4 作为中间顶点遍历各队顶点,更新后的表格为:

而对于顶点 V5 来说,和顶点 V0 和 V1 相类似,所不同的是,V5 只有入度,没有出度,所以对各队顶点的距离不会产生影 响。最终采用弗洛伊德算法求得的各个顶点之间的最短路径如上图所示。

3.2弗洛伊德算法代码实现(C语言完整代码)

#include <stdio.h>
#define MAX_VERtEX_NUM 20 //顶点的最大个数
#define VRType int //表示弧的权值的类型
#define VertexType int //图中顶点的数据类型
#define INFINITY 65535
typedef struct {VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据VRType arcs[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //二维数组,记录顶点之间的关系int vexnum,arcnum; //记录图的顶点数和弧(边)数
}MGraph;
typedef int PathMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //用于存储最短路径中经过的顶点的下标
typedef int ShortPathTable[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //用于存储各个最短路径的权值和
//根据顶点本身数据,判断出顶点在二维数组中的位置
int LocateVex(MGraph * G,VertexType v){int i=0;
//遍历一维数组,找到变量 vfor (; i<G->vexnum; i++) {if (G->vexs[i]==v) {break;}}
//如果找不到,输出提示语句,返回-1if (i>G->vexnum) {printf("no such vertex.\n"); return -1;}return i;}
//构造有向网
void CreateUDG(MGraph *G){ scanf("%d,%d",&(G->vexnum),&(G->arcnum));for (int i=0; i<G->vexnum; i++) { scanf("%d",&(G->vexs[i]));}for (int i=0; i<G->vexnum; i++) {for (int j=0; j<G->vexnum; j++) {G->arcs[i][j]=INFINITY;}}
for (int i=0; i<G->arcnum; i++) {int v1,v2,w;scanf("%d,%d,%d",&v1,&v2,&w);int n=LocateVex(G, v1);int m=LocateVex(G, v2);if (m==-1 ||n==-1) {printf("no this vertex\n"); return;}G->arcs[n][m]=w;}
}
//弗洛伊德算法,其中 P 二维数组存放各对顶点的最短路径经过的顶点,D 二维数组存储各个顶点之间的权值
void ShortestPath_Floyed(MGraph G,PathMatrix *P,ShortPathTable *D){//对 P 数组和 D 数组进行初始化for (int v=0; v<G.vexnum; v++) {for (int w=0; w<G.vexnum; w++) {(*D)[v][w]=G.arcs[v][w];(*P)[v][w]=-1;}}//拿出每个顶点作为遍历条件for (int k=0; k<G.vexnum; k++) {//对于第 k 个顶点来说,遍历网中任意两个顶点,判断间接的距离是否更短for (int v=0; v<G.vexnum; v++) {for (int w=0; w<G.vexnum; w++) {//判断经过顶点 k 的距离是否更短,如果判断成立,则存储距离更短的路径if ((*D)[v][w] > (*D)[v][k] + (*D)[k][w]) {(*D)[v][w]=(*D)[v][k] + (*D)[k][w];(*P)[v][w]=k;}}}}
}
int main(){MGraph G;CreateUDG(&G);PathMatrix P;ShortPathTable D;ShortestPath_Floyed(G, &P, &D);for (int i=0; i<G.vexnum; i++) {for (int j=0; j<G.vexnum; j++) {printf("%d ",P[i][j]);}printf("\n");}for (int i=0; i<G.vexnum; i++) {for (int j=0; j<G.vexnum; j++) {printf("%d ",D[i][j]);}printf("\n");}return 0;
}

对于这个例子

//输入
6,8
0
1
2
3
4
5
0,5,100
0,4,30
0,2,10
1,2,5
2,3,50
3,5,10
4,3,20
4,5,60
//输出
-1 -1 -1 4 -1 4
-1 -1 -1 2 -1 3
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
65535 65535 10 50 30 60
65535 65535 5 55 65535 65
65535 65535 65535 50 65535 60
65535 65535 65535 65535 65535 10
65535 65535 65535 20 65535 30
65535 65535 65535 65535 65535 65535

3.3弗洛伊德算法小结

迪杰斯特拉主要解决从网(带权图)中某一顶点计算到其它顶点之间的最短路径问题。如果求有向网 中每一对顶点之间的最短路径,使用迪杰斯特拉算法的解决思路是:以每一个顶点为源点,执行迪杰斯特拉算法。这样可以求得 每一对顶点之间的最短路径。也可以使用弗洛伊德算法,该算法相比于使用迪杰斯特拉算法在解决此问题上的时间复杂度虽然相同,都为 O(n3),但是弗洛伊德算法的实现形式更简单。

本篇博客转载C语言中文网

最短路径之迪杰斯特拉(Dijkstra 算法)弗洛伊德算法(C语言完整代码实现)相关推荐

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

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

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

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

  3. 难难难!如何求图的某一顶点到其他顶点最短距离?迪杰斯特拉Dijkstra和弗洛伊德Floyd要上场了

    对于无权图来说,可以使用广度优先遍历算法BFS,实现求单源路径最短.但是,如果图带了权值,求这种最短路径可以通过经典的Dijkstra(迪杰斯特拉)算法或者是Floyd(弗洛伊德)算法来求解.当然,这 ...

  4. 最短路径:迪杰斯特拉(Dijkstra)算法图解

    Dijkstra算法可以求解带权图中最短路径. 算法思想:将所有节点分为两个区域,已知区域和未知区域.最开始的时候,将起点加入到已知区域,其他点加入未知区域,比较已知区域到未知区域的所有连线,最短的路 ...

  5. 迪杰斯特拉(Dijkstra) —— 最短路算法

    Dijkstra是最短路基础算法之一(还有判负环的SPFA和多源最短路的Floyd),但在正常情况下Dijkstra是最快的,也同样是最难打的(其实都不是很难),接下来我们来谈谈具体算法: 1.适用范 ...

  6. 图的最短路径之迪杰斯特拉算法和弗洛伊德算法

    文章目录 一.迪杰斯特拉(Dijkstra)算法 1.定义描述 2.算法思想 3.算法步骤 4.算法图解 二.弗洛伊德(Floyd)算法 1.定义描述 2.算法思想 3.算法步骤 三.Dijkstra ...

  7. Java 图的最短路径问题-迪杰斯特拉算法VS弗洛伊德算法

    1.迪杰斯特拉算法VS弗洛伊德算法 迪杰斯特拉算法通过选定的被访问顶点,求出从出发访问顶点到其他顶点的最短路径: 弗洛伊德算法中每一个顶点都是出发访问点,所以需要将每一个顶点看做被访问顶点,求出从每一 ...

  8. Java迪杰斯特拉(Dijkstra)算法与弗洛伊德(Floyd)算法

    1.Java迪杰斯特拉(Dijkstra)算法与弗洛伊德(Floyd)算法 1.1 迪杰斯特拉(Dijkstra)算法 1.1.1 迪杰斯特拉(Dijkstra)算法介绍 迪杰斯特拉(Dijkstra ...

  9. 059.迪杰斯特拉(Dijkstra)算法的原理以及解决最短路径问题

    1. 迪杰斯特拉(Dijkstra)算法的原理 1.1. 算法应用场景-最短路径问题 1.2. 基本介绍 1.3. 步骤详解 1.4. 思路解析 1.5. 图解步骤 2. 迪杰斯特拉(Dijkstra ...

  10. 单源最短路径算法java_数据结构 - 单源最短路径之迪杰斯特拉(Dijkstra)算法详解(Java)...

    给出一个图,求某个端点(goal)到其余端点或者某个端点的最短路径,最容易想到的求法是利用DFS,假设求起点到某个端点走过的平均路径为n条,每个端点的平均邻接端点为m,那求出这个最短路径使用DFS算法 ...

最新文章

  1. 卷积神经网络(CNN)张量(图像)的尺寸和参数计算(深度学习)
  2. 【SLAM】ORB-SLAM:让人Orz的SLAM
  3. nginx学习七 高级数据结构之动态数组ngx_array_t
  4. 凯里一中2021高考成绩查询,贵州凯里第一中学2021年排名
  5. 终极利器|一篇文章讲清楚Python虚拟环境
  6. Django forms组件
  7. win10 设置游戏全屏
  8. 数据科学 IPython 笔记本 7.11 聚合和分组
  9. 自然语言处理——BERT情感分类实战(一)之预处理
  10. redis04-----Hash 哈希数据类型相关命令
  11. 视频编码中的PAFF和MBAFF的区别 转自:http://blog.csdn.net/kerryhung/article/details/4433256...
  12. 什么是嵌入式服务器?为什么要使用嵌入式服务器? -- java面试
  13. select 向上弹起
  14. OLED显示与LCD显示的区别
  15. AGC012B Splatter Painting
  16. linux r语言内存查看,R语言统计与分布的相关知识
  17. html 感叹号代码,HTML电子邮件中的感叹号
  18. 美团java面经校招本科_美团java社招经历分享
  19. 科大奥锐密立根油滴实验数据_大学物理实验--密立根油滴实验报告
  20. 缓冲区溢出分析第06课:W32Dasm缓冲区溢出分析

热门文章

  1. zabbix监控搭建
  2. 小五思科技术学习笔记之SSH
  3. eclipse The current branch is not configured for pull No value for key remote.origin
  4. Git使用技巧(3)-- 远程操作
  5. Mysql学习总结(25)——MySQL外连接查询
  6. python data analysis | python数据预处理(基于scikit-learn模块)
  7. AS3深拷贝数据对象(1)深拷贝基本数据类型
  8. Linux网络基本网络配置
  9. 计算机供应链结构,面向供应链管理的二维条码设计-计算机系统结构专业毕业论文.docx...
  10. 史上最全的SpringBatch学习教程