图->最短路径->单源最短路径(迪杰斯特拉算法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 }
代码运行
/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) 编辑 收藏 举报