View Post


自己总结的关于图论的一些算法实现(C语言实现,有较详细注释,800行左右)

(提示,是C语言实现。)

代码仅供学习使用,如果觉得不错的话,点个赞喔~~Thanks

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #define TRUE 1
  5 #define FALSE 0
  6 #define inf 99999
  7 typedef  int BOOL;
  8 typedef  int ElemType;
  9 typedef struct mGraph
 10 {
 11     ElemType **a;     //邻接矩阵
 12     int n;            //图的当前顶点数
 13     int e;            //图的当前边数
 14     ElemType noEdge;  //两顶点间无边时的值
 15 }MGraph;
 16 typedef struct queue
 17 {
 18     int front;      //队头
 19     int rear;       //队尾
 20     int MaxSize;     //队的最大容量
 21     ElemType *element;  //存储元素
 22 }Queue;
 23 typedef struct eNode
 24 {
 25     int adjVex;       //与任意顶点u相邻接的顶点
 26     ElemType w;       //边的权值
 27     struct eNode *nextArc;  //指向下一个结点
 28 }ENode;
 29 typedef struct lGraph
 30 {
 31     int n;               //图当前的顶点数
 32     int e;               //图当前的边数
 33     ENode **a;           //指向一维指针数组
 34 }LGraph;
 35 typedef struct stack
 36 {
 37     int top;       //栈顶
 38     int maxSize;   //栈所能装最大元素量
 39     ElemType *element;  //数据
 40 }Stack;
 41 
 42 int vis_m[1000];   //邻接矩阵对应图的标记数组。 vis_m[i]用于表示 编号为i的结点是否被使用过,没有使用过则 =0,否则 =1;
 43 int vis_l[1000];   //邻接表对应图的标记数组。 vis_m[i]用于表示 编号为i的结点是否被使用过,没有使用过则 =0,否则 =1;
 44 int path[1000];    //用于记录最佳路径上的结点编号
 45 int Min_Time=999999;       //用于记录最佳路径所花费的时间,初始化时尽量使它大
 46 int count;        //记录最佳路径上结点的个数
 47 int load[1000];   //用于图的遍历,让遍历路径数组的储存空间足够大
 48 int cnt;          //用于表示load[]数组的下标
 49 
 50 void Clear_Flag() //标记清零操作
 51 {
 52     int i;
 53     cnt=0;
 54     for( i=0;i<1000;i++ )
 55         load[i]=vis_m[i]=vis_l[i]=0;
 56 }
 57 
 58 void Create_S( Stack *s,int size )  //创建栈
 59 {
 60     s->maxSize=size;
 61     s->top=-1;       //现在栈还是空的,所以栈顶为“-1”
 62     s->element=(ElemType*)malloc(sizeof(ElemType));
 63 }
 64 void Destroy_S( Stack *s )  //销毁栈
 65 {
 66     s->top=-1;
 67     s->maxSize=0;
 68     free(s->element);  //因为只申请了一次,所以只释放一次
 69 }
 70 BOOL IsEmpty_S( Stack *s )  //判断栈是否为空栈
 71 {
 72     return s->top==-1;
 73 }
 74 BOOL IsFull_S( Stack *s )  //判断一个栈是否已满
 75 {
 76     return s->top==s->maxSize-1;
 77 }
 78 void Top_S( Stack *s,ElemType *x )  //获取栈顶元素
 79 {
 80     if( IsEmpty_S(s) )  //如果栈为空
 81     {
 82         printf("现在栈为空栈,没有东西可取喔。\n");
 83         return ;
 84     }
 85     *x=s->element[s->top];
 86 }
 87 void Push_S( Stack *s,ElemType x )  //入栈
 88 {
 89     if( IsFull_S(s) )  //如果栈已满
 90     {
 91         printf("现在栈已满,不能再装东西啦喔。\n");
 92         return ;
 93     }
 94     s->top++;
 95     s->element[s->top]=x;
 96 }
 97 void Pop_S( Stack *s ) //删除栈顶元素
 98 {
 99     if( IsEmpty_S(s) )  //如果栈为空
100     {
101         printf("现在栈为空栈喔。\n");
102         return ;
103     }
104     s->top--;
105 }
106 void Clear_S( Stack *s )  //清空栈,但不释放空间
107 {
108     s->top=-1;
109 }
110 
111 void Create_Q( Queue *q,int size )  //创建队列
112 {
113     q->front=q->rear=0;   //创建时,这里为0,都指向队头
114     q->MaxSize=size;
115     q->element=(ElemType*)malloc(size*sizeof(ElemType));
116 }
117 void Destroy_Q( Queue *q )  
118 {
119     q->front=q->rear=-1;
120     q->MaxSize=0;
121     free(q->element);
122 }
123 void Clear_Q( Queue *q )
124 {
125     q->front=q->rear=0;   //注意这里也是0,清空时,让它俩都指向队头
126 }
127 BOOL IsEmpty_Q( Queue *q )  //判断队列是否为空
128 {
129     return q->front==q->rear;
130 }
131 BOOL IsFull_Q( Queue *q )   //判断队列是否已满
132 {
133     return (q->rear+1)%q->MaxSize==q->front;  
134 }
135 void Push_Q( Queue *q,ElemType x )
136 {
137     if( IsFull_Q(q) )
138     {
139         printf("队列已满,无法再进行入队操作!\n");
140         return ;
141     }
142     q->rear=(q->rear+1)%q->MaxSize;
143     q->element[q->rear]=x;
144 }
145 void DeQueue_Q( Queue *q )   //删除队头元素,出队操作
146 {
147     if( IsEmpty_Q(q) )
148     {
149         printf("队列为空,无法再进行出队操作!\n");
150         return ;
151     }
152     q->front=(q->front+1)%q->MaxSize;
153 }
154 void Front_Q( Queue *q,ElemType *x )  //获取队头元素
155 {
156     if( IsEmpty_Q(q) )
157     {
158         printf("队列为空,无法获取队头元素!\n");
159         return ;
160     }
161     *x=q->element[(q->front+1)%q->MaxSize];
162 }
163 
164 
165 void Init_M( MGraph *mg,int v,ElemType noEdge )   //v为顶点数,noEdge为:两顶点无边时的值
166 {
167     int i,j;
168     mg->n=v;
169     mg->e=0;           //初始化时没有边
170     mg->noEdge=noEdge;
171     mg->a=(ElemType**)malloc(mg->n*sizeof(ElemType*));      //申请二维动态空间
172     for( i=0;i<mg->n;i++ )
173     {
174         mg->a[i]=(ElemType*)malloc(mg->n*sizeof(ElemType));  //申请一维动态空间
175         for( j=0;j<mg->n;j++ )
176             mg->a[i][j]=mg->noEdge;
177         mg->a[i][i]=0;    
178     }
179     printf("邻接矩阵已成功初始化!\n");
180     return ;
181 }
182 void Destroy_M( MGraph *mg )
183 {
184     int i;
185     for( i=0;i<mg->n;i++ )   //申请了几次一维动态空间就要释放几次
186         free(mg->a[i]);
187     free(mg->a);
188     printf("邻接矩阵已经成功撤销!\n");
189     return ;
190 }
191 BOOL Find_M_E( MGraph *mg,int u,int v )   //邻接矩阵的边的搜索,u为出发点,v为被指向点
192 {
193     if( u<0||u>=mg->n||v<0||v>=mg->n||u==v )   //增强代码的健壮性,判断错误输出
194     {
195         printf("请输入正确的 你所要找查的边的两端的结点值!\n");
196         return FALSE;
197     }
198     if( mg->a[u][v]==mg->noEdge )   //如果 u→v 没有边
199         return FALSE;
200     else              
201         return TRUE;
202 }
203 void Insert_M_E( MGraph *mg,int u,int v,ElemType x )   //邻接矩阵的边的插入
204 {
205     if( u<0||u>=mg->n||v<0||v>=mg->n||u==v )   //增强代码的健壮性,判断错误输出
206     {
207         printf("请输入正确的 你所要找插入的边的两端的结点值!\n");
208         return ;
209     }
210     if( Find_M_E(mg,u,v) )   //如果该边的已经有了,则不能在进行重复插入操作
211     {
212         printf("该边已经在图中存在了,请勿重复插入!\n");
213     }
214     else
215     {
216         mg->a[u][v]=x;  //执行插入操作
217         mg->e++;
218     }
219 }
220 BOOL Delete_M_E( MGraph *mg,int u,int v )   //邻接矩阵的边的删除
221 {
222     if( u<0||u>=mg->n||v<0||v>=mg->n||u==v )   //增强代码的健壮性,判断错误输出
223     {
224         printf("请输入正确的 你所要找删除的边的两端的结点值!\n");
225         return FALSE;
226     }
227     if( !Find_M_E(mg,u,v) )   //如果该边的在图中本身就没有,则不能在进行删除操作
228     {
229         printf("该边在图中不存在!\n");
230         return FALSE;
231     }
232     else
233     {
234         mg->a[u][v]=mg->noEdge;
235         mg->e--;
236         return TRUE;
237     }
238 }
239 
240 //以上述邻接矩阵为存储结构,编写程序,实现图的深度优先遍历、宽度优先遍历
241 void Dfs_M( MGraph *mg,int u )  //u为开始遍历的起点
242 {
243     int i=0;
244     if( !vis_m[u] )
245     {
246         printf("%3d ",u);
247         load[cnt++]=u;
248         vis_m[u]=1;    //编号为u的结点 的标记改变
249     }
250     while( i<mg->n )
251     {
252         if( !vis_m[i]&&mg->a[u][i]!=mg->noEdge&&u!=i )  //如果u→编号为i的结点有边,并且结点i未被“走过”(即标记过)
253         {  
254             Dfs_M( mg,i );
255         }
256         i++;
257     }
258 }
259 void Bfs_M( MGraph *mg,int u ) //u为开始遍历的起点
260 {
261     int i;
262     Queue q;
263     Create_Q(&q,mg->n);  //创建队列,最大容量要+1才行
264     vis_m[u]=1;            //编号为u的结点 的标记改变
265     Push_Q(&q,u);           //编号为u的结点 压入
266     while( !IsEmpty_Q(&q) )  //只要队列还不为空,就继续执行
267     {
268         Front_Q(&q,&u);       //将队头元素传给u
269         printf("%3d ",u);      //打印
270         load[cnt++]=u;
271         DeQueue_Q(&q);        //将队头元素去掉
272         for( i=0;i<mg->n;i++ )
273         {
274            if( !vis_m[i]&&mg->a[u][i]!=mg->noEdge&&u!=i )  //如果u→编号为i的结点有边,并且结点i未被“走过”(即标记过)
275            {
276              Push_Q(&q,i);
277              vis_m[i]=1;   //标记改变
278             }
279         }
280     }
281     Destroy_Q(&q);   //撤销队列
282     return ;
283 }
284 
285 void Init_L( LGraph *lg,int size )   //x表示顶点数的意思
286 {
287     int i;
288     lg->n=size;
289     lg->e=0;       //刚开始图是没有边的
290     lg->a=(ENode**)malloc(lg->n*sizeof(ENode*));
291     for( i=0;i<lg->n;i++ )
292         lg->a[i]=NULL;      //将指针数组a置空
293     return ; 
294 }
295 void Destroy_L( LGraph *lg )
296 {
297     ENode *front,*cur;    //指针cur用于释放,指针front用于遍历
298     int i;
299     for( i=0;i<lg->n;i++ )
300     {
301         front=lg->a[i];   //指针front指向顶点i的单链表的第一个边结点
302         cur=front;
303         while( cur )   
304         {
305             front=front->nextArc;   
306             free(cur);
307             cur=front;
308         }
309     }
310     free( lg->a );       //释放一维指针数组a的存储空间
311     return ;
312 }
313 BOOL Find_L_E( LGraph *lg,int u,int v )   //邻接表 边的搜索
314 {
315     ENode *fp=lg->a[u];
316     if( u<0||u>=lg->n||v<0||v>=lg->n||u==v )   //增强代码的健壮性,判断错误输出
317     {
318         printf("请输入正确的 你所要找查的边的两端的结点值!\n");
319         return FALSE;
320     }
321     while( fp&&fp->adjVex!=v )   
322     {
323         fp=fp->nextArc;
324     }
325     if( fp!=NULL )   //若找到了这条边
326         return TRUE;
327     else
328         return FALSE;
329 }
330 void Insert_L_E( LGraph *lg,int u,int v,ElemType w )
331 {
332     ENode *fp;   //front作为前驱指针,指向插入位置的前一个结点
333     if( u<0||u>=lg->n||v<0||v>=lg->n||u==v )   //增强代码的健壮性,判断错误输出
334     {
335         printf("请输入正确的 你所要找插入的边的两端的结点值!\n");
336         return ;
337     }
338     if( Find_L_E(lg,u,v) )   //如果在图中找到这条边
339     {
340         printf("该边已经在图中存在了,请勿重复插入!\n");
341         return ;
342     }
343     else
344     {
345         fp=(ENode*)malloc(sizeof(ENode));  //为新的边结点分配存储空间
346         fp->adjVex=v;
347         fp->w=w;
348         fp->nextArc=lg->a[u];         //将新的边结点插入单链表的最前面
349         lg->a[u]=fp;
350         lg->e++;            //细节
351     }
352 }        
353 BOOL Delete_L_E( LGraph *lg,int u,int v )
354 {
355     ENode *front,*fp;   //一般情况下,前驱结点front指向删除结点fp 的前一个结点
356     if( u<0||u>=lg->n||v<0||v>=lg->n||u==v )   //增强代码的健壮性,判断错误输出
357     {
358         printf("请输入正确的 你所要删除的边的两端的结点值!\n");
359         return FALSE;
360     }
361     front=NULL;
362     fp=lg->a[u];
363     while( fp&&fp->adjVex!=v )     //找查待删除的边是否存在
364     {
365         front=fp;
366         fp=fp->nextArc;
367     }
368     if( fp==NULL )  //指针fp为空,说明该边不存在
369     {
370         printf("你所要删除的边在图中不存在!\n");
371         return FALSE;
372     }
373     if( front==NULL )   //前驱结点为空,说明,要删除的边在表头
374     {
375         lg->a[u]=fp->nextArc;
376         free(fp);
377     }
378     else       //否则要删除的边不在表头
379     {
380         front->nextArc=fp->nextArc;
381         free(fp);
382     }
383     lg->e--;    //细节
384     return TRUE;
385 }
386 
387 /* 以上述邻接表为存储结构,编写程序,实现图的深度、宽度优先遍历 */
388 void Dfs_L( LGraph *lg,int u )  //u为开始遍历的起点 
389 {
390     ENode *fp;
391     printf("%3d ",u);
392     load[cnt++]=u;
393     vis_l[u]=1;        //标记改变
394     for( fp=lg->a[u];fp;fp=fp->nextArc )
395     {
396         if( !vis_l[fp->adjVex] )   //只要下一结点未被访问过
397         {
398             Dfs_L(lg,fp->adjVex);
399         }
400     }
401     return ;
402 }
403 void Bfs_L( LGraph *lg,int u )
404 {
405     ENode *fp;      //移动指针,在邻接表上移动
406     Queue q;
407     Create_Q(&q,lg->n);
408     Push_Q(&q,u);   //将编号为u的结点入队
409     while( !IsEmpty_Q(&q) )   //只要队列还不为空,就继续执行
410     {
411         Front_Q(&q,&u);
412         DeQueue_Q(&q);
413         printf("%3d ",u);       //打印
414         load[cnt++]=u;
415         vis_l[u]=1;             //标记改变
416         for( fp=lg->a[u];fp;fp=fp->nextArc )
417         {
418             if( !vis_l[fp->adjVex] )   //只要与u连接的结点未被访问过,就让他们入队
419             {
420                 Push_Q(&q,fp->adjVex);
421                 vis_l[fp->adjVex]=1;  //标记改变
422             }
423         }
424     }
425     Destroy_Q(&q);  //撤销队列
426     return ;
427 }
428 
429 void Print_M( MGraph *mg )   //邻接矩阵打印
430 {
431     int i,j;
432     printf("\n\n该图的邻接矩阵为:\n");
433     for( i=0;i<mg->n;i++ )
434     {
435         for( j=0;j<mg->n;j++ )
436         {
437             if( mg->a[i][j]!=mg->noEdge )
438                 printf("%d\t",mg->a[i][j]);
439             else
440                 printf("*\t");
441         }
442         printf("\n");
443     }
444     printf("(注:“*”代表结点u到结点v没有边)\n");
445 }
446 void Print_L( LGraph *lg )     //邻接表打印
447 {
448     ENode *fp;    //移动指针,在邻接表上移动
449     int i;
450     printf("\n\n该图的邻接表为:(注:“ |2| 1-50 ”代表的意思是,表头结点2,有指向结点1的边,边的值为50)\n");
451     for( i=0;i<lg->n;i++ )
452     {
453         printf("表头结点: |%d|",i);
454         for( fp=lg->a[i];fp;fp=fp->nextArc )
455         {
456             printf("%3d-%-3d ",fp->adjVex,fp->w);
457         }
458         printf("\n");
459     }
460 }
461 void Print_Indegree_1( MGraph *mg )   //(邻接矩阵)每个结点的入度打印,load[]为遍历路径
462 {
463     int i,j,ans;
464     int *fp;
465     for( i=0;i<cnt;i++ )
466     {
467         ans=0;
468         for( j=0;j<cnt;j++ )
469         {
470             fp=&(mg->a[j][ load[i] ]);  //以第一排的每个元素 作起始地址 进行向下搜索
471             if( *fp!=0&&*fp!=mg->noEdge )
472                 ans++;    
473         }
474         printf("%3d ",ans);
475     }
476 }
477 void Print_Outdegree_1( MGraph *mg )   //(邻接矩阵)每个结点的出度打印,load[]为遍历路径
478 {
479     int i,j,ans;      //ans表示结点度数
480     int *fp;
481     for( i=0;i<cnt;i++ )
482     {
483         ans=0;
484         fp=mg->a[ load[i] ];
485         for( j=0;j<cnt;j++ )
486         {
487             if( *fp!=0&&*fp!=mg->noEdge )
488               ans++;
489             fp++;     //指针向右移动
490         }
491         printf("%3d ",ans);
492     }
493 }
494 void Print_Indegree_2( LGraph *lg )   //(邻接表)每个结点的入度打印,load[]为遍历路径
495 {
496     int i;
497     ENode *fp;
498     int *in_degree=(int*)malloc(lg->n*sizeof(int));    //用数组in_degree[]记录每个结点的入度
499     for( i=0;i<lg->n;i++ )    //初始化
500         in_degree[i]=0;
501     for( i=0;i<lg->n;i++ )
502     {
503         for( fp=lg->a[ load[i] ];fp;fp=fp->nextArc )
504         {
505             in_degree[fp->adjVex]++;    //编号为 fp->adjVex 的结点的编号 的入度加1
506         }
507     }
508     for( i=0;i<lg->n;i++ )
509     {
510         printf("%3d ",in_degree[ load[i] ] );
511     }
512 }
513 void Print_Outdegree_2( LGraph *lg )   //(邻接表)每个结点的出度打印,load[]为遍历路径
514 {
515     int i,ans;      //ans表示结点度数
516     ENode *fp;
517     for( i=0;i<lg->n;i++ )
518     {
519         ans=0;
520         for( fp=lg->a[ load[i] ];fp;fp=fp->nextArc )
521         {
522             ans++;
523         }
524         printf("%3d ",ans);
525     }
526 }
527 
528 void Bfs_Judge( LGraph *lg,int u )    //用于判断是否是强连通图的辅助函数
529 {
530     ENode *fp;      //移动指针,在邻接表上移动
531     Queue q;
532     Create_Q(&q,lg->n);
533     Push_Q(&q,u);   //将编号为u的结点入队
534     while( !IsEmpty_Q(&q) )   //只要队列还不为空,就继续执行
535     {
536         Front_Q(&q,&u);
537         DeQueue_Q(&q);
538         cnt++;
539         vis_l[u]=1;             //标记改变
540         for( fp=lg->a[u];fp;fp=fp->nextArc )
541         {
542             if( !vis_l[fp->adjVex] )   //只要与u连接的结点未被访问过,就让他们入队
543             {
544                 Push_Q(&q,fp->adjVex);
545                 vis_l[fp->adjVex]=1;  //标记改变
546             }
547         }
548     }
549     Destroy_Q(&q);  //撤销队列
550     return ;
551 }
552 BOOL Judge_QiangLiTongTu( LGraph *lg )   //判断是否是强连通图(针对于有向图)
553 {
554     int i;
555     for( i=0;i<lg->n;i++ )
556     {
557         Clear_Flag();        //标记清零操作
558         Bfs_Judge(lg,i);
559         if( cnt!=lg->n )     //若任意一对顶点之间都存在路径,则以某一结点为起点宽度遍历后,路径长度cnt应该为lg->n (注:cnt为全局变量)              
560             return FALSE;    //不是连通图,返回FALSE
561     }
562     return TRUE;   //每个结点都满足,这说明是强连通图
563 }
564 
565 void In_Degree_Helper( int *in_degree,LGraph *lg )
566 {
567     ENode *fp;
568     int i;
569     for( i=0;i<lg->n;i++ )
570         in_degree[i]=0;   //先初始化
571     for( i=0;i<lg->n;i++ )
572     {
573         for( fp=lg->a[i];fp;fp=fp->nextArc )
574         {
575             in_degree[ fp->adjVex ]++;   //编号为fp->adjVex的结点的入度加1
576         }
577     }
578 }
579 void TopSort( LGraph *lg )   //拓扑排序
580 {
581     ENode *fp;
582     int *in_degree,i,top_node;
583     Stack sta;
584     Create_S(&sta,lg->n);
585     in_degree=(int*)malloc(lg->n*sizeof(int));
586     In_Degree_Helper(in_degree,lg);      //初始化该数组
587     for( i=0;i<lg->n;i++ )
588     {
589         if( in_degree[i]==0 )
590             Push_S(&sta,i);
591     }
592     while( !IsEmpty_S(&sta) )
593     {
594         Top_S(&sta,&top_node);
595         Pop_S(&sta);                          //这条语句不能放到for循环下面!不然栈里的元素不能被覆盖,要出大问题
596         load[cnt++]=top_node;
597         for( fp=lg->a[top_node];fp;fp=fp->nextArc )
598         {
599             in_degree[fp->adjVex]--;            //更新编号为fp->adjVex的结点的入度
600             if( in_degree[fp->adjVex]==0 )      //并判断编号为fp->adjVex的结点入度是否为零,是则放入栈
601                 Push_S(&sta,fp->adjVex);
602         }
603     }
604     if( cnt==lg->n )
605     {
606         printf("\n该图的拓扑排序为:");
607         for( i=0;i<lg->n;i++ )
608             printf("%3d ",load[i]);
609     }
610     else
611     {
612         printf("该图中存在有向回路,不能拓扑排序。\n");
613     }
614 }
615 
616 /*
617   编写程序,实现智能交通中的最佳路径选择:设有n个地点,编号为0~n-1,m条路径的起点、终点
618   和代价由用户输入提供,采用上述邻接表为存储结构,寻找最佳路径方案(花费时间最少)
619 */
620 void DFS_PLF( LGraph *lg,Stack *s,int v,int Time )   //v为终点,起点已经装进了栈里了
621 {
622     ENode *fp;   //fp为移动指针,在邻接表上移动
623     int t,i;
624     Top_S(s,&t);
625     if( t==v&&Time<Min_Time )  //终止条件:栈顶元素为终点。并且所花时间 比 以前记录的所花最少时间还要小
626     {
627         Min_Time=Time;
628         for( i=0;i<=s->top;i++ )
629             path[i]=s->element[i];   //记录当前最佳路径
630         count=i;
631         return ;
632     }
633     for( fp=lg->a[t];fp;fp=fp->nextArc )
634     {
635         if( !vis_l[fp->adjVex] )   //如果 编号为t的结点指向的 编号为fp->adjVex的结点未被访问过
636         {
637             Push_S(s,fp->adjVex);  //入栈
638             vis_l[fp->adjVex]=1;  //标记改变
639             DFS_PLF(lg,s,v,Time+fp->w);   //时间代价要加fp->w
640             vis_l[fp->adjVex]=0;  //标记回溯
641             Pop_S(s);            //出栈(回溯)
642         }
643     }
644 }
645 void Prefect_Load_Find( LGraph *lg,int u,int v )  //最佳路径找查(花费时间最少),思路:深度优先搜索
646 {
647     Stack s;
648     int i;
649     Create_S(&s,lg->n);
650     Push_S(&s,u);
651     vis_l[u]=1;      //标记改变,编号为u的结点已被访问
652     DFS_PLF( lg,&s,v,0 );
653     printf("从 编号为%d的起点 到 编号为%d的终点的最佳路径(花费时间最少)为:",u,v);
654     for( i=0;i<count;i++ )
655         printf("%d ",path[i]);
656     printf("\n所花费的时间为:%d\n",Min_Time);
657 }
658 void Experiment_5()        //入口函数:智能交通的最佳路径的实现(花费时间最少)
659 {
660     int n;       //n个地点 ,编号为0~n-1
661     int m;       //m条路径
662     int u,v,w;   //路径的起点u、终点v和代价w
663     int i;
664     LGraph lg;
665     Clear_Flag();   //标记清零操作
666     printf("请分别输入地点个数n和路径个数m:");
667     scanf("%d%d",&n,&m);
668     Init_L(&lg,n);    //初始化邻接表,n个顶点
669     i=m;
670     while( i>0 )
671     {
672         printf("请分别输入第%d条路径的起点、终点和时间代价:",m-i+1);
673         scanf("%d%d%d",&u,&v,&w);
674         Insert_L_E(&lg,u,v,w);
675         i--;
676     }
677     printf("请输入你想找哪两个结点的最佳路径:(分别输入起点和终点)");
678     scanf("%d%d",&u,&v);
679     if( u<0||u>=lg.n||v<0||v>=lg.n||u==v )   //增强代码的健壮性,判断错误输出
680     {
681         printf("请输入正确的 你所要找查最佳路径的起点和终点!\n");
682         return ;
683     }
684     Prefect_Load_Find( &lg,u,v );
685     return ;
686 }
687 
688 void M_Grapg()   //入口函数:邻接矩阵的实现(额外包含矩阵打印出、入度计算) 
689 {
690     int i,u,v,w,n;
691     MGraph mg;
692     printf("请输入该图的结点数:");
693     scanf("%d",&n);
694     Init_M(&mg,n,-9999);
695     printf("输入u为-999时结束。\n");
696     while( 1 )
697     {
698         scanf("%d%d%d",&u,&v,&w);
699         if( u==-999 )
700             break;
701         Insert_M_E(&mg,u,v,w);
702     }
703     Clear_Flag();   //标记清零操作
704     printf("\n矩阵的 深度遍历 结果为:\n");
705     printf("结点  ");
706     for( i=0;i<mg.n;i++ )
707     {
708         if(!vis_m[i])
709             Dfs_M(&mg,i);
710     }
711     printf("\n入度  ");
712     Print_Indegree_1(&mg);   //每个结点的入度打印
713     printf("\n出度  ");
714     Print_Outdegree_1(&mg);   //每个结点的出度打印
715     Print_M(&mg);            //邻接矩阵打印51
716     printf("\n请分别输入需要删除的边的两端的结点值:");
717     scanf("%d%d",&u,&v);
718     if( !Delete_M_E(&mg,u,v) )
719         return ;
720     printf("删除边后矩阵的 宽度遍历 结果为:\n");
721     printf("结点  ");
722     Clear_Flag();        //标记清零操作
723     for( i=0;i<mg.n;i++ )
724     {
725         if(!vis_m[i])
726             Dfs_M(&mg,i);
727     }
728     printf("\n入度  ");
729     Print_Indegree_1(&mg);   //每个结点的入度打印
730     printf("\n出度  ");
731     Print_Outdegree_1(&mg);   //每个结点的出度打印
732     printf("\n");
733     Print_M(&mg);         //邻接矩阵打印
734     Destroy_M(&mg);
735 }
736 void L_Graph()  //入口函数:邻接表的实现(额外包含强连通图判断、邻接表打印、拓扑排序)
737 {
738     int i,u,v,w,count=0,n;   //n为结点数
739     LGraph lg;
740     printf("请输入该图的结点数:");
741     scanf("%d",&n);
742     Init_L(&lg,n);
743     printf("输入u为-999时结束。\n");
744     while( 1 )
745     {
746         scanf("%d%d%d",&u,&v,&w);
747         if( u==-999 )
748             break;
749         Insert_L_E(&lg,u,v,w);
750     }
751     Clear_Flag();   //标记清零操作
752     printf("\n矩阵的 深度遍历 结果为:\n结点  ");
753     for( i=0;i<lg.n;i++ )
754     {
755         if( !vis_l[i] )
756             Dfs_L(&lg,i);
757     }
758     printf("\n入度  ");
759     Print_Indegree_2(&lg);   //(邻接表)每个结点的入度打印
760     printf("\n出度  ");
761     Print_Outdegree_2(&lg);   //(邻接表)每个结点的出度打印
762     Print_L(&lg);            //打印邻接表
763     if( Judge_QiangLiTongTu(&lg) )
764         printf("\n该图 是 强连通图。\n");
765     else
766         printf("\n该图 不是 强连通图。\n");
767     Clear_Flag();   //标记清零操作
768     TopSort(&lg);
769     printf("\n\n请分别输入需要删除的边的两端的结点值:");
770     scanf("%d%d",&u,&v);
771     if( !Delete_L_E(&lg,u,v) )
772         return ;
773     Clear_Flag();   //标记清零操作
774     printf("删除后的图的 宽度遍历 为:\n结点  ");
775     for( i=0;i<lg.n;i++ )
776     {
777         if( !vis_l[i] )
778             Dfs_L(&lg,i);
779     }
780     printf("\n入度  ");
781     Print_Indegree_2(&lg);   //(邻接表)每个结点的入度打印
782     printf("\n出度  ");
783     Print_Outdegree_2(&lg);   //(邻接表)每个结点的出度打印
784     Print_L(&lg);           //打印邻接表
785     Destroy_L(&lg);
786 }
787 
788 void Main_Menu()        //主菜单打印
789 {
790     printf("+--------------------------------------------------------------------------+\n");
791     printf("|                  主菜单                                                  |\n");
792     printf("|             1、邻接矩阵的实现(额外包含矩阵打印出、入度计算)              |\n");
793     printf("|             2、邻接表的实现(额外包含强连通图判断、邻接表打印、拓扑排序)  |\n");
794     printf("|             3、智能交通的最佳路径的实现(花费时间最少)                    |\n");
795     printf("|             0、退出                                                      |\n");
796     printf("+--------------------------------------------------------------------------+\n");
797 } 
798 
799 int main()
800 {
801     int choice;
802     do
803     {
804         system("cls");
805         Main_Menu();
806         printf("请输入你的选择:\n");
807         scanf("%d",&choice);
808         switch(choice)
809         {
810         case 1: M_Grapg();      //邻接矩阵的实现(额外包含矩阵打印出、入度计算)
811                 break;
812         case 2: L_Graph();       //邻接表的实现(额外包含强连通图判断、邻接表打印、拓扑排序)
813                 break;
814         case 3: Experiment_5();     //智能交通的最佳路径的实现(花费时间最少)
815                 break;
816         }
817         system("pause");
818     }while(choice);
819     return 0;
820 }

                 

如果您觉得不错的话,点个赞,编者再接再厉~ Thanks~ ^_^

 

版权声明:本文为Wang-dou-dou原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Wang-dou-dou/p/14189915.html