图的应用——最短路径(Dijkstra算法)

一、什么是最短路径

从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,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最优子结构性质 :任意两点之间的最短路径的子路径仍然是最短路径。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值