圖的基本算法


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

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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM