图的基本算法
近两个星期,回顾数据结构时又把图的相关知识复习了一下,顺便为了提高编码能力,将基本算法也都实现了一下。现将实例附录如下:
1)要实现的算法
①建立图的存储结构
②深度优先搜索和广度优先搜索
③求图的最小生成树
④拓扑排序
⑤最短路径
2)存储结构设计
本系统采用图结构(mgraph)存储抽象操作的信息。其中,各结点间的邻接关系用图的邻接矩阵类型(adjmatrix)存储。顶点信息用结构数组(vexs)存储。其中每个数据元素师一个结构变量,包括一些基本信息。
此外,本系统还设置了三个全局变量:visited[]数组用于存储顶点是否被访问标记;d[]用于存放边上的权值或者是存储查找路径顶点的编号;campus是一个图结构的全局变量
3)功能设计
本程序一共设置了9个子功能菜单,图的初始化由函数initgraph()实现,依据读入的图的顶点个数和边的个数。分别初始化图结构中图的顶点向量数组和图的邻接矩阵。9个功能设计描述如下:
①建立有向图。有向图的建立有由BuildAdjacencyList()实现。当用户选择该功能时,用户要手动输入该图的信息。从而建立有向图。
②输出邻接表。邻接表的输出有函数ShowAdjacencyList()实现。当用户选择该项功能时,系统即以邻接表的形式输出各顶点所连接的点。
③输出顶点的度。顶点读的输出由函数ShowAdjacencyListDegree()实现。当用户选择该功能时,系统即将每个顶点的度以数字的形式输出。
④进行拓扑排序。拓扑排序功能的实现由函数TopologicalSortAdjacencyList()完成。一旦选择,就会进行排序并输出。
⑤深度优先遍历。采用DFS算法进行深度优先遍历,遍历完成后,将遍历得到的结点有序输出。
⑥广度优先遍历。采用BFS算法进行广度优先遍历,遍历完成后,将遍历得到的结点有序输出。
⑦无向图最小生成树。最小生成树的算法实现由函数AdjacencyListPrim()完成。该函数采用Prim算法对邻接矩阵求最小生成树并输出。
⑧有向图求最短路径。最短路径的实现采用函数AdjacencyListDijkstra()完成。该函数采用的是Dijkstra 算法对邻接矩阵对各顶点到其他顶点的最短距离。并依次输出。
4)测试结果
①菜单界面
②建立有向图
③输出该邻接表
④输出顶点的度
⑤进行拓扑排序
⑥深度优先搜索
⑦广度优先搜索
⑧最短路径
5)源代码附录
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #define MAX_VERTEX_NUM 100 5 #define MAX 1000000000 6 typedef struct Arcnode /////邻接表除头结点以外的结点 7 { 8 int adjvex; 9 struct Arcnode *nextarc; 10 int weight; 11 }ArcNode; 12 typedef struct Vnode /////邻接表的头结点 13 { 14 int data; 15 struct Arcnode *fistarc; 16 }Vnode; 17 Vnode AdjList[MAX_VERTEX_NUM]; ////有多个头结点,定义为数组形式了 18 19 int flag[MAX_VERTEX_NUM]; 20 int count[MAX_VERTEX_NUM]; 21 int map[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; ///////无向图邻接矩阵 22 int map2[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; ////////有向图的邻接矩阵 23 int map3[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; ///////"临时"的邻接矩阵 24 int topocount[MAX_VERTEX_NUM]; 25 int topoflag[MAX_VERTEX_NUM]; 26 int num[MAX_VERTEX_NUM]; /////用于存储深度优先遍历和广度优先遍历的结果 27 28 int K; //////表示遍历过的节点数 29 int choose; //////主菜单选择变量 30 int Num,Number; //////Num表示顶点的个数,number表示的为边的个数 31 32 33 void Build_VAdjacencyList() ///////建立并初始化头结点 34 { 35 int i; 36 for(i=0;i<Num;i++) 37 { 38 AdjList[i].data=i+1; 39 AdjList[i].fistarc=NULL; 40 } 41 } 42 void BuildAdjacencyList() ///////////建立邻接表,当然,在建立邻接表的同时也建立了此图的图的有向图邻接矩阵以及无向图的邻接矩阵 43 { 44 int a,b,c,i,j; 45 ArcNode *p,*s; 46 printf("请输入图中顶点的个数:\n"); 47 scanf("%d",&Num); 48 Build_VAdjacencyList(); 49 for(i=0;i<Num;i++) 50 { 51 for(j=0;j<Num;j++) 52 if(i==j) 53 { 54 map[i][j]=0; 55 map2[i][j]=0; 56 } 57 else 58 { 59 map[i][j]=MAX; 60 map2[i][j]=MAX; 61 } 62 } 63 printf("请输入图中边的个数:\n"); 64 scanf("%d",&Number); 65 printf("请输入各条边的两个顶点以及边的权值:\n"); 66 for(i=0;i<Number;i++) 67 { 68 scanf("%d%d%d",&a,&b,&c); 69 if(map2[a-1][b-1]>c) ///////建立此图的有向图的邻接矩阵 70 { 71 map2[a-1][b-1]=c; 72 } 73 74 75 if(map[a-1][b-1]>c) /////这里的2个if为建立此图的无向图的邻接矩阵 76 map[a-1][b-1]=c; 77 if(map[b-1][a-1]>c) ///// 78 map[b-1][a-1]=c; 79 80 81 p=AdjList[a-1].fistarc; /////以下是建立邻接表 82 if(p==NULL) 83 { 84 s=(ArcNode *)malloc(sizeof(ArcNode)); 85 s->adjvex=b-1; 86 s->weight=c; 87 s->nextarc=NULL; 88 AdjList[a-1].fistarc=s; 89 } 90 else 91 { 92 while(p->nextarc!=NULL) 93 { 94 p=p->nextarc; 95 } 96 s=(ArcNode *)malloc(sizeof(ArcNode)); 97 s->adjvex=b-1; 98 s->weight=c; 99 s->nextarc=NULL; 100 p->nextarc=s; 101 } 102 } 103 104 } 105 void ShowAdjacencyList() ///////以邻接表的形式输出各顶点所连接的点 106 { 107 if(Num==0) 108 printf("请先建立有向图!\n"); 109 else 110 { 111 int i; 112 ArcNode *p; 113 for(i=0;i<Num;i++) 114 { 115 printf("从%d直接可达的点有:",i+1); 116 p=AdjList[i].fistarc; 117 while(p!=NULL) 118 { 119 printf("%d、",p->adjvex+1); 120 p=p->nextarc; 121 } 122 printf("\n"); 123 } 124 } 125 } 126 void ShowAdjacencyListDegree() //////////////////以邻接表的形式输出各顶点的度 127 { 128 if(Num==0) 129 printf("请先建立有向图!\n"); 130 else 131 { 132 int i,j,sum; 133 ArcNode *p; 134 for(i=0;i<Num;i++) 135 { 136 sum=0; 137 p=AdjList[i].fistarc; 138 //出度 139 while(p!=NULL) 140 { 141 sum++; 142 p=p->nextarc; 143 } 144 //入度 145 for(j=0;j<Num;j++) 146 { 147 if(j!=i) 148 { 149 p=AdjList[j].fistarc; 150 while(p!=NULL) 151 { 152 153 if(p->adjvex==i) 154 sum++; 155 p=p->nextarc; 156 } 157 } 158 } 159 printf("顶点%d的度为:%d\n",i,sum); 160 } 161 } 162 } 163 void TopologicalSortAdjacencyList() ///////邻接表的拓扑排序 164 { 165 if(Num==0) 166 printf("请先建立有向图!\n"); 167 else 168 { 169 memset(topocount,0,sizeof(topocount)); 170 memset(topoflag,0,sizeof(topoflag)); 171 int i,sum,k=0; 172 ArcNode *p; 173 sum=0; 174 while(sum<Num) 175 { 176 for(i=0;i<Num;i++) 177 { 178 if(topoflag[i]==0) 179 { 180 p=AdjList[i].fistarc; 181 while(p!=NULL) 182 { 183 topoflag[p->adjvex]=1; 184 p=p->nextarc; 185 } 186 } 187 } 188 for(i=0;i<Num;i++) 189 { 190 if(topoflag[i]==0) 191 { 192 topoflag[i]=2; 193 topocount[sum]=i+1; 194 sum++; 195 break; 196 } 197 } 198 if(i==Num+1) 199 { 200 printf("此有向图有环!\n"); 201 k=1; 202 break; 203 } 204 for(i=0;i<Num;i++) 205 { 206 if(topoflag[i]==1) 207 topoflag[i]=0; 208 } 209 } 210 if(k==0) 211 { 212 for(i=0;i<Num;i++) 213 printf("%d ",topocount[i]); 214 printf("\n"); 215 } 216 } 217 } 218 void DFS(ArcNode *s) 219 { 220 ArcNode *p; 221 while(s!=NULL) 222 { 223 if(flag[s->adjvex]==0) 224 s=s->nextarc; 225 else 226 { 227 flag[s->adjvex]=0; 228 num[K]=s->adjvex; 229 K++; 230 p=AdjList[s->adjvex].fistarc; 231 DFS(p); 232 s=s->nextarc; 233 } 234 } 235 } 236 void DFSAdjacencyList() ///////////////////对邻接表进行深度优先遍历 237 { 238 if(Num==0) 239 printf("请先建立有向图!\n"); 240 else 241 { 242 int i,k; 243 K=0; 244 ArcNode *p; 245 for(i=0;i<Num;i++) 246 flag[i]=1; 247 for(k=0;k<Num;k++) 248 { 249 if(flag[k]==1) 250 { 251 num[K]=k; 252 K++; 253 p=AdjList[k].fistarc; 254 DFS(p); 255 } 256 } 257 printf("深度优先遍历的顺序为:\n"); 258 for(i=0;i<Num;i++) 259 printf("%d ",num[i]+1); 260 printf("\n"); 261 } 262 } 263 void BFSAdjacencyList() ///////对邻接表进行广度优先遍历 264 { 265 if(Num==0) 266 printf("请先建立有向图!\n"); 267 else 268 { 269 int i,j; 270 ArcNode *p; 271 K=0; 272 j=0; 273 for(i=0;i<Num;i++) 274 flag[i]=1; 275 memset(count,0,sizeof(count)); 276 for(i=0;i<Num;i++) 277 { 278 if(flag[i]==1) 279 { 280 flag[i]=0; 281 num[K]=i; 282 K++; 283 while(j<K) 284 { 285 p=AdjList[num[j]].fistarc; 286 j++; 287 while(p!=NULL) 288 { 289 if(flag[p->adjvex]==1) 290 { 291 num[K]=p->adjvex; 292 K++; 293 flag[p->adjvex]=0; 294 } 295 p=p->nextarc; 296 } 297 } 298 } 299 } 300 printf("广度优先遍历的顺序为:\n"); 301 for(i=0;i<Num;i++) 302 printf("%d ",num[i]+1); 303 printf("\n"); 304 } 305 } 306 void AdjacencyListPrim() ///////////////////用Prim算法对邻接矩阵求最小生成树 307 { 308 if(Num==0) 309 printf("请先建立有向图!\n"); 310 else 311 { 312 int min1,pi,i,j,ans=0; 313 for(i=0;i<Num;i++) 314 { 315 flag[i]=0; 316 count[i]=map[0][i]; 317 } 318 flag[0]=1; 319 count[0]=0; 320 for(i=1;i<Num;i++) 321 { 322 min1=MAX; 323 for(j=0;j<Num;j++) 324 { 325 if(flag[j]==0&&count[j]<min1) 326 { 327 min1=count[j]; 328 pi=j; 329 } 330 } 331 if(min1==MAX) 332 { 333 printf("图不连通!\n"); 334 return; 335 } 336 flag[pi]=1; 337 for(j=0;j<Num;j++) 338 { 339 if(flag[j]==0&&count[j]>map[pi][j]) 340 count[j]=map[pi][j]; 341 } 342 } 343 for(i=0;i<Num;i++) 344 { 345 ans+=count[i]; 346 } 347 printf("%d\n",ans); 348 } 349 } 350 void AdjacencyListDijkstra() ////////////对邻接矩阵对各顶点到其他顶点的最短距离,在此用的是Dijkstra 算法 351 { 352 if(Num==0) 353 printf("请先建立有向图!\n"); 354 else 355 { 356 int min1,pi,i,j,k; 357 for(k=0;k<Num;k++) 358 { 359 memset(flag,0,sizeof(flag)); 360 memset(count,0,sizeof(count)); 361 for(i=0;i<Num;i++) 362 { 363 flag[i]=0; 364 count[i]=map2[k][i]; 365 } 366 flag[k]=1; 367 count[k]=0; 368 for(i=1;i<Num;i++) 369 { 370 min1=MAX; 371 for(j=0;j<Num;j++) 372 { 373 if(flag[j]==0&&count[j]<min1) 374 { 375 min1=count[j]; 376 pi=j; 377 } 378 } 379 flag[pi]=1; 380 for(j=0;j<Num;j++) 381 { 382 if(flag[j]==0&&count[j]>count[pi]+map2[pi][j]) 383 count[j]=count[pi]+map2[pi][j]; 384 } 385 } 386 for(i=0;i<Num;i++) 387 { 388 map3[k][i]=count[i]; 389 } 390 } 391 for(i=0;i<Num;i++) 392 { 393 for(j=0;j<Num;j++) 394 { 395 if(i==j) 396 continue; 397 if(map3[i][j]!=MAX) 398 printf("顶点%d与顶点%d之间的最短距离为:%d\n",i+1,j+1,map3[i][j]); 399 else 400 printf("顶点%d与顶点%d之间的最短距离为:+∞\n",i+1,j+1); 401 } 402 403 } 404 } 405 } 406 void ShowMenu() //////////////////////菜单 407 { 408 printf("-----------------------------------------------------\n"); 409 printf("|对图的操作如下: |\n"); 410 printf("-----------------------------------------------------\n"); 411 printf("| 1.建立有向图 ; 2.输出该临接表 |\n"); 412 printf("| 3.输出个顶点的度 ; 4.进行拓扑排序 |\n"); 413 printf("| 5.深度优先遍历 ; 6.广度优先遍历 |\n"); 414 printf("| 7.无向图最小生成树 ; 8.有向图求最短路径 |\n"); 415 printf("| 0.退出 |\n"); 416 printf("-----------------------------------------------------\n"); 417 printf("请选择想要进行的操作:\n"); 418 scanf("%d",&choose); 419 420 } 421 int main() ///////////////////////////////////主函数 422 { 423 Num=0; 424 Number=0; 425 ShowMenu(); 426 while(1) 427 { 428 if(choose==0) 429 break; 430 else if(choose==1) 431 { 432 BuildAdjacencyList(); 433 ShowMenu(); 434 } 435 else if(choose==2) 436 { 437 ShowAdjacencyList(); 438 ShowMenu(); 439 } 440 else if(choose==3) 441 { 442 ShowAdjacencyListDegree(); 443 ShowMenu(); 444 } 445 else if(choose==4) 446 { 447 TopologicalSortAdjacencyList(); 448 ShowMenu(); 449 } 450 else if(choose==5) 451 { 452 DFSAdjacencyList(); 453 ShowMenu(); 454 } 455 else if(choose==6) 456 { 457 BFSAdjacencyList(); 458 ShowMenu(); 459 } 460 else if(choose==7) 461 { 462 AdjacencyListPrim(); 463 ShowMenu(); 464 } 465 else if(choose==8) 466 { 467 AdjacencyListDijkstra(); 468 ShowMenu(); 469 } 470 471 } 472 return 0; 473 }