图的基本算法

  近两个星期,回顾数据结构时又把图的相关知识复习了一下,顺便为了提高编码能力,将基本算法也都实现了一下。现将实例附录如下:

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 }

 

posted @ 2015-05-10 20:23  CSUER  阅读(4832)  评论(0编辑  收藏  举报