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 }

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

  1. Light OJ - 1026 - Critical Links(图论-Tarjan算法求无向图的桥数) - 带详细注释

     原题链接   无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点:然后再把所有点遍历一遍 ...

  2. 魔方阵算法及C语言实现

    1 魔方阵概念 填充的,每一行.每一列.对角线之和均相等的方阵,阶数n = 3,4,5….魔方阵也称为幻方阵. 例如三阶魔方阵为: 魔方阵有什么的规律呢? 魔方阵分为奇幻方和偶幻方.而偶幻方又分为是4 ...

  3. 一个UUID生成算法的C语言实现 --- WIN32版本 .

    一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...

  4. 无限大整数相加算法的C语言源代码

    忙里偷闲,终于完成了无限大整数相加算法的C语言代码,无限大整数相加算法的算法分析在这里. 500位的加法运行1000次,不打印结果的情况下耗时0.036秒,打印结果的情况下耗时16.285秒. 下面是 ...

  5. 数据结构算法集---C++语言实现

    //数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...

  6. 1164: 零起点学算法71——C语言合法标识符(存在问题)

    1164: 零起点学算法71——C语言合法标识符 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 10 ...

  7. 【最全】经典排序算法(C语言)

    算法复杂度比较: 算法分类 一.直接插入排序 一个插入排序是另一种简单排序,它的思路是:每次从未排好的序列中选出第一个元素插入到已排好的序列中. 它的算法步骤可以大致归纳如下: 从未排好的序列中拿出首 ...

  8. PID算法(c 语言)(转)

    PID算法(c 语言)(来自老外) #include <stdio.h> #include<math.h> //定义PID 的结构体 struct _pid { int pv; ...

  9. 一个UUID生成算法的C语言实现——WIN32版本

    源: 一个UUID生成算法的C语言实现——WIN32版本

  10. 排序算法总结(C语言版)

    排序算法总结(C语言版) 1.    插入排序 1.1     直接插入排序 1.2     Shell排序 2.    交换排序 2.1     冒泡排序 2.2     快速排序 3.    选择 ...

随机推荐

  1. PDF文件处理助手 3.3.2版本更新

    本次更新内容如下: 1.修复部分PDF在"去水印"-"文字水印"-"模式3"下识别不到的问题. 2.修复部分情况下可能无法正确加载授权的问题 ...

  2. Java多线程中的wait/notify通信模式

    前言 最近在看一些JUC下的源码,更加意识到想要学好Java多线程,基础是关键,比如想要学好ReentranLock源码,就得掌握好AQS源码,而AQS源码中又有很多Java多线程经典的一些应用:再比 ...

  3. Java安全之JNI绕过RASP

    Java安全之JNI绕过RASP 0x00 前言 前面一直想看该JNI的相关内容,但是发现JNI的资料还是偏少.后面发现JNI在安全中应用非常的微妙,有意思. 0x01 JNI概述 JNI的全称叫做( ...

  4. vue 项目在 IE11 里呈现空白,不兼容的问题解决方案

    我用vue 2.6.11版本编写的项目,在谷歌浏览器上运行的好好地,但是放到ie11浏览器上却是一片空白. 这个问题遇到的时候,我是蒙蔽了,抓紧去搜了搜百度,百度上的答案倒是都很统一. 都是说ie不兼 ...

  5. CentOS基础命令使用技巧-1

    less用法 g快速返回文件首部 G快速到文本最末端 /当前行向下搜索 ?当前行向上搜索 n显示下一个 q退出 cp用法 r拷贝一个目录必须加这个 rm用法 r删除目录 f强制删除,r后面删除不存在的 ...

  6. CentOS创建管理LVM分区(挂载新分区)

    来源: CentOS 8.0 创建管理LVM分区(挂载新分区) https://www.iwmyx.cn/centos80cjgllvmfa.html 1.查看可用磁盘 fdisk -l 2.新盘(/ ...

  7. 第6.4节 Python动态表达式计算:eval函数详述

    在Python动态执行的函数中,eval是用于执行表达式计算的函数,这个函数用于执行字符串中包含的一个表达式或其编译后对应的代码,不能适用于执行Python语句和完整的代码. 一.    语法 1.  ...

  8. 老猿学5G扫盲贴:3GPP规范文档命名规则及同系列文档阅读指南

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 在学习5G规范过程中,有些内容把握不定的时候,有时 ...

  9. PyQt学习随笔:使用PyCharm+PyQt开发遇到的坑

    最近三天,老猿都在使用PyCharm+QtDesigner工具,通过xlwings读取Excel的数据到TableView中显示的练习,本以为很容易的一件事,断断续续持续了三天时间才终于成功.在这个过 ...

  10. 1、pytorch写的第一个Linear模型(原始版,不调用nn.Modules模块)

    参考: https://github.com/Iallen520/lhy_DL_Hw/blob/master/PyTorch_Introduction.ipynb 模拟一个回归模型,y = X * w ...