近兩個星期,回顧數據結構時又把圖的相關知識復習了一下,順便為了提高編碼能力,將基本算法也都實現了一下。現將實例附錄如下:
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 }