一、什么是最短路径
从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。
我使用的是Dijkstra算法来计算最短路径。
二、Dijkstra
迪杰斯特拉算法采用的是贪心算法,Dijkstra算法算法思路是设置一个集合S记录已求得的最短路径的顶点,初始时把源点V0(图中的某个顶点)放入S,集合S每并入一个新顶点 Vii,都要修改源点V0到集合 V-S 中顶点当前的最短路径长度值。
三、代码实现
下面的代码是根据我的大作业题目来写的
题目描述:
7.图的应用
请根据学校地图,任意选择一个起点和一个终点,并根据上图所示,选择起点到终点的最短路径。
要求如下:
1)构造一个图,并规划起点到终点的路线,简述构建这条路线的思路。
2) 用算法实现你的分析思路,并输出路径。(包括代码和运行结果的截图)
3) 分析算法的性能,至少包括时间复杂度和空间复杂度等。
1.#include <stdio.h>
2.#define V 20 //顶点的最大个数
3.#define INFINITY 65535
4.typedef struct {
5. char vexs[V]; //存储图中顶点数据
6. int arcs[V][V]; //二维数组,记录顶点之间的关系
7. int vexnum, arcnum; //记录图的顶点数和弧(边)数
8.}MGraph;
9.
10.int LocateVex(MGraph *, char);
11.void CreateDG(MGraph *);
12.void Dijkstra_minTree(MGraph, int, int p[V], int D[V]);
13.void User_selection(MGraph, int p[V], int D[V]);
14.
15.//根据顶点本身数据,判断出顶点在二维数组中的位置
16.int LocateVex(MGraph * G, char v) {
17. int i = 0;
18. //遍历一维数组,找到变量v
19. for (; i < G->vexnum; i++) {
20. if (G->vexs[i] == v) {
21. break;
22. }
23. }
24. //如果找不到,输出提示语句,返回-1
25. if (i > G->vexnum) {
26. printf("no such vertex.\n");
27. return -1;
28. }
29. return i;
30.}
31.//构造无向有权图
32.void CreateDG(MGraph *G) {
33. printf("输入图的顶点数和边数:");
34. scanf("%d %d", &(G->vexnum), &(G->arcnum));
35. getchar();
36. printf("输入各个顶点:");
37. for (int i = 0; i < G->vexnum; i++) {
38. scanf("%c", &(G->vexs[i]));
39. getchar();
40. }
41. for (int i = 0; i < G->vexnum; i++) {
42. for (int j = 0; j < G->vexnum; j++) {
43. G->arcs[i][j] = INFINITY;
44. }
45. }
46. printf("输入各个边的数据:\n");
47. for (int i = 0; i < G->arcnum; i++) {
48. char v1, v2;
49. int w;
50. scanf("%c %c", &v1, &v2);
51. getchar();
52. scanf("%d",&w);
53. getchar();
54. int n = LocateVex(G, v1);
55. int m = LocateVex(G, v2);
56. if (m == -1 || n == -1) {
57. return;
58. }
59. G->arcs[n][m] = w;
60. G->arcs[m][n] = w;
61. }
62.}
63.//迪杰斯特拉算法,v0表示有向网中起始点所在数组中的下标
64.void Dijkstra_minTree(MGraph G, int v0, int p[V], int D[V]) {
65. int final[V];//为各个顶点配置一个标记值,用于确认该顶点是否已经找到最短路径
66. //对各数组进行初始化
67. for (int v = 0; v < G.vexnum; v++) {
68. final[v] = 0;
69. D[v] = G.arcs[v0][v];
70. p[v] = 0;
71. }
72. //由于以v0位下标的顶点为起始点,所以不用再判断
73. D[v0] = 0;
74. final[v0] = 1;
75. int k = 0;
76. for (int i = 0; i < G.vexnum; i++) {
77. int min = INFINITY;
78. //选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
79. for (int w = 0; w < G.vexnum; w++) {
80. if (!final[w]) {
81. if (D[w] < min) {
82. k = w;
83. min = D[w];
84. }
85. }
86. }
87. //设置该顶点的标志位为1,避免下次重复判断
88. final[k] = 1;
89. //对v0到各顶点的权值进行更新
90. for (int w = 0; w < G.vexnum; w++) {
91. if (!final[w] && (min + G.arcs[k][w] < D[w])) {
92. D[w] = min + G.arcs[k][w];
93. p[w] = k;//记录各个最短路径上存在的顶点
94. }
95. }
96. }
97.}
98.//用户样例测试
99.void User_selection(MGraph G, int P[V], int D[V]){
100. printf("请选择您的一个起点和一个终点:");
101. char start, arrive;
102. scanf("%c %c", &start, &arrive);
103. int m = LocateVex(&G, start);
104. int n = LocateVex(&G, arrive);
105. Dijkstra_minTree(G, m, P, D);
106. if(D[n] == INFINITY){
107. printf("无法达到该位置!");
108. return ;
109. }
110. printf("%c - %c的最短路径中的顶点有:", G.vexs[n], G.vexs[m]);
111. printf(" %c-", G.vexs[n]);
112. int j = n;
113. //由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可 得到各个最短路径上的所有顶点
114. while (G.vexs[P[j]] != G.vexs[0]) {
115. printf("%c-", G.vexs[P[j]]);
116. j = P[j];
117. }
118. printf("A\n");
119.
120. printf("源点到%c点的最短路径长度为:\n", arrive);
121. printf("%c - %c : %d \n", G.vexs[0], G.vexs[n], D[n]);
122.}
123.
124.int main() {
125. MGraph G;
126. CreateDG(&G);
127. int P[V] = { 0 }; // 记录顶点 0 到各个顶点的最短的路径
128. int D[V] = { 0 }; // 记录顶点 0 到各个顶点的总权值
129. User_selection(G, P, D);
130. return 0;
131.}
运行结果:
(1).可以到达的情况:
输入图的顶点数和边数:14 14
输入各个顶点:A B C D E F G H I J K L M N
输入各个边的数据:
A B 1
A C 1
A D 3
B G 2
C E 1
D M 3
E F 1
F I 2
G J 5
I L 3
J L 2
K L 2
M N 5
N K 6
请选择您的一个起点和一个终点:A J
J - A的最短路径中的顶点有: J-G-B-A
源点到J点的最短路径长度为:
A - J : 8
进程已结束,退出代码0
(2).无法到达的情况:
输入图的顶点数和边数:14 14
输入各个顶点:A B C D E F G H I J K L M N
输入各个边的数据:
A B 1
A C 1
A D 3
B G 2
C E 1
D M 3
E F 1
F I 2
G J 5
I L 3
J L 2
K L 2
M N 5
N K 6
请选择您的一个起点和一个终点:A H
无法达到该位置!
进程已结束,退出代码0
Dijkstra算法的性能:
3.1时间复杂度 : O(N^2),其中N是图中节点的数量,但是可以使用优先队列等数据结构来提高算法的效率,使其时间复杂度降至O(E log N),其中E是图中边的数量。
3.2空间复杂度 : O(N), 其中N是图中节点的数量。需要用一个距离字典来存储每个节点到起点的最短距离,和一个优先队列来选择下一个访问的节点。
3.3最优子结构性质 :任意两点之间的最短路径的子路径仍然是最短路径。