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

 文字描述

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

 

  单源点的最短路径问题: 给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。迪杰斯特拉(Dijkstra)提出了一个按路径长度递增的次序产生最短路径的算法。迪杰斯特拉(Dijkstra)算法描述如下:

  

 

示意图

  

  

 

   

 

算法分析

  结合代码实现部分分析这个算法的运行时间。本博客写的代码,其时间复杂度为n^3, 但是理论上应该只为n^2

 

代码实现

  1 //
  2 // Created by lady on 19-1-3.
  3 //
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 
  7 #define INFINITY        100000    //最大值
  8 #define MAX_VERTEX_NUM    20        //最大顶点数
  9 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
 10 typedef struct ArcCell{
 11     int weight;    //该弧相关信息的指针
 12 }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM], PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM], ShortPathTable[MAX_VERTEX_NUM];
 13 typedef struct VertexType{
 14     char data[10];
 15 }VertexType;
 16 typedef struct{
 17     VertexType vexs[MAX_VERTEX_NUM];    //顶点向量
 18     AdjMatrix arcs;        //邻接矩阵
 19     int vexnum, arcnum;    //图的当前顶点数和弧数
 20     GraphKind kind;        //图的种类标志
 21 }MGraph;
 22 
 23 /*
 24  * 根据顶点信息, 返回该顶点在图中的位置, 如果返回-1表示顶点不存在
 25  */
 26 static int LocateVex(MGraph *G, char data[])
 27 {
 28     int i = 0;
 29     for(i=0; i<G->vexnum; i++){
 30         if(!strncmp(G->vexs[i].data, data, strlen(G->vexs[i].data))){
 31             return i;
 32         }
 33     }
 34     return -1;
 35 }
 36 
 37 /*
 38  * 用邻接矩阵作为存储结构,创建有向网
 39  */
 40 static int CreateGraphDN(MGraph *G)
 41 {
 42     printf("用邻接矩阵创建有向网,输入顶点数,弧数:");
 43     G->kind = DN;
 44     scanf("%d,%d", &G->vexnum, &G->arcnum);
 45     if(G->vexnum > MAX_VERTEX_NUM){
 46         printf("错误:顶点数不能超过%d!!\n", MAX_VERTEX_NUM);
 47         return -1;
 48     }
 49     int i = 0, j = 0, k = 0;
 50     char v1[10] = {0}, v2[10]={0}, info[10] = {0};
 51     char tmp[30] = {0};
 52     for(i=0; i<G->vexnum; i++){
 53         printf("输入第%d个顶点: ", i);
 54         memset(G->vexs[i].data, 0, sizeof(G->vexs[0].data));
 55         scanf("%s", G->vexs[i].data);
 56         for(j=0; j<G->vexnum; j++){
 57             G->arcs[i][j].weight = INFINITY;
 58         }
 59         G->arcs[i][i].weight = 0;
 60     }
 61     for(k=0; k<G->arcnum; k++){
 62         printf("输入第%d条弧(顶点1, 顶点2): ", k);
 63         memset(tmp, 0, sizeof(tmp));
 64         scanf("%s", tmp);
 65         sscanf(tmp, "%[^','],%[^','],%s[^\\n]", v1, v2, info);
 66         i = LocateVex(G, v1);
 67         j = LocateVex(G, v2);
 68         if(i<0 || j<0 || (!atoi(info))){
 69             printf("错误:顶点%s或者%s不存在, 或者权值信息%s不对!\n", v1, v2, info);
 70             return -1;
 71         }
 72         G->arcs[i][j].weight = atoi(info);
 73     }
 74     return 0;
 75 }
 76 static void printMatrix(int vexnum, VertexType vexs[], int (*arcs)[MAX_VERTEX_NUM])
 77 {
 78     int i = 0, j = 0;
 79     printf("\t");
 80     for(i=0; i<vexnum; i++){
 81         printf("%s\t", vexs[i].data);
 82     }
 83     printf("\n");
 84     for(i=0; i<vexnum; i++){
 85         printf("%s\t", vexs[i].data);
 86         for(j=0; j<vexnum; j++){
 87             if(arcs[i][j] == INFINITY){
 88                 printf("INF\t");
 89             }else{
 90                 printf("%d\t", arcs[i][j]);
 91             }
 92         }
 93         printf("\n");
 94     }
 95     return ;
 96 }
 97 
 98 static void printArchs(int vexnum, VertexType vexs[], AdjMatrix arcs)
 99 {
100     int i = 0, j = 0;
101     printf("\t");
102     for(i=0; i<vexnum; i++){
103         printf("%s\t", vexs[i].data);
104     }
105     printf("\n");
106     for(i=0; i<vexnum; i++){
107         printf("%s\t", vexs[i].data);
108         for(j=0; j<vexnum; j++){
109             if(arcs[i][j].weight == INFINITY){
110                 printf("INF\t");
111             }else{
112                 printf("%d\t", arcs[i][j].weight);
113             }
114         }
115         printf("\n");
116     }
117     return ;
118 }
119 
120 #include <string.h>
121 /*
122  * Dijkstra迪杰斯特拉算法
123  * 从有向网G的顶点v0出发,求v0到其余顶点v的最短路径P[v]及其带权长度D[v].weight
124  * 若P[v][w].weight为TRUE(1),则w是从v0到v当前求得最短路径上的顶点。
125  * final[v]为TRUE(1),当且仅当v属于S,即已经求得从v0到v的最短路径
126  */
127 void ShortestPath_DIJ(MGraph *G, int v0)
128 {
129     int v = 0;
130     int w = 0;
131     int i = 0;
132     int j = 0;
133     int final[MAX_VERTEX_NUM] = {0};
134     int min = 0;
135     int P[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
136     ShortPathTable D;
137 
138     for(v=0; v<G->vexnum; ++v){
139         D[v].weight = G->arcs[v0][v].weight;
140         //设为空路径
141         for(w=0; w<G->vexnum; ++w){
142             P[v][w] = 0;
143         }
144         if(D[v].weight < INFINITY){
145             P[v][v0] = 1;
146             P[v][v] = 1;
147         }
148     }
149     //初始化,v0顶点属于S集
150     D[v0].weight = 0;
151     final[v0] = 1;
152     //开始主循环,每次求得v0到某个v顶点的最短路径,并加v到s集
153     //其余G->vexnum-1个顶点
154     for(i=1; i<G->vexnum; ++i){
155         //min存放当前离v0顶点最短的距离
156         min = INFINITY;
157         for(w=0; w<G->vexnum; w++){
158             if(!final[w]){
159                 //顶点w在V-S中
160                 if(D[w].weight < min){
161                     //顶点v0更近
162                     min = D[w].weight;
163                     v = w;
164                 }
165             }
166         }
167         if(min == INFINITY)
168             break;
169         //离v0最短的顶点v加入S集合
170         final[v] = 1;
171         //更新当前最短路径和距离
172         for (w = 0; w < G->vexnum; w++) {
173             if (!final[w] && (min + G->arcs[v][w].weight < D[w].weight)) {
174                 //修改D[w]和P[w],w属于V-S
175                 D[w].weight = min + G->arcs[v][w].weight;
176                 for(j=0; j<G->vexnum; j++){
177                     P[w][j] = P[v][j];
178                 }
179                 P[w][w] = 1;
180             }
181         }
182     }
183 
184     printf("\n打印最短路径:\n");
185     printMatrix(G->vexnum, G->vexs, P);
186 
187     printf("\n打印%s到其余顶点的带权长度:\n", G->vexs[v0].data);
188     for(i=0; i<G->vexnum; i++){
189         if(D[i].weight == INFINITY){
190             printf("%s,INF\t", G->vexs[i].data);
191         }else {
192             printf("%s,%d\t", G->vexs[i].data, D[i].weight);
193         }
194     }
195     printf("\n");
196     return ;
197 }
198 
199 int main(int argc, char *argv[])
200 {
201     //以邻接矩阵为存储结构创建有向网
202     MGraph G;
203     if(CreateGraphDN(&G) < 0){
204         return -1;
205     }
206     printf("\n打印该图中的信息:\n");
207     printArchs(G.vexnum, G.vexs, G.arcs);
208     //Dijkstra迪杰斯特拉算法求单源最短路径
209     ShortestPath_DIJ(&G, 0);
210     return 0;
211 }
单源最短路径(Dijkstra)

 

代码运行

/home/lady/CLionProjects/untitled/cmake-build-debug/untitled
用邻接矩阵创建有向网,输入顶点数,弧数:6,8
输入第0个顶点: v0
输入第1个顶点: v1
输入第2个顶点: v2
输入第3个顶点: v3
输入第4个顶点: v4
输入第5个顶点: v5
输入第0条弧(顶点1, 顶点2): v0,v5,100
输入第1条弧(顶点1, 顶点2): v0,v4,30
输入第2条弧(顶点1, 顶点2): v0,v2,10
输入第3条弧(顶点1, 顶点2): v1,v2,5
输入第4条弧(顶点1, 顶点2): v2,v3,50
输入第5条弧(顶点1, 顶点2): v4,v5,60
输入第6条弧(顶点1, 顶点2): v4,v3,20
输入第7条弧(顶点1, 顶点2): v3,v5,10

打印该图中的信息:
    v0    v1    v2    v3    v4    v5    
v0    0    INF    10    INF    30    100    
v1    INF    0    5    INF    INF    INF    
v2    INF    INF    0    50    INF    INF    
v3    INF    INF    INF    0    INF    10    
v4    INF    INF    INF    20    0    60    
v5    INF    INF    INF    INF    INF    0    

打印最短路径:
    v0    v1    v2    v3    v4    v5    
v0    1    0    0    0    0    0    
v1    0    0    0    0    0    0    
v2    1    0    1    0    0    0    
v3    1    0    0    1    1    0    
v4    1    0    0    0    1    0    
v5    1    0    0    1    1    1    

打印v0到其余顶点的带权长度:
v0,0    v1,INF    v2,10    v3,50    v4,30    v5,60    

Process finished with exit code 0

 

posted on 2019-01-04 18:05  LiveWithACat  阅读(572)  评论(0编辑  收藏  举报