[关闭]
@yanglt7 2018-10-21T15:49:06.000000Z 字数 15161 阅读 678

09_图

数据结构和算法


9.1 图的定义

9.2 图的顶点与边之间的关系

9.3 图的存储结构

9.3.1 邻接矩阵(无向图)

顶点数组: V0 V1 V2 V3
~ V0 V1 V2 V3
V0 0 1 1 1
V1 1 0 1 0
V2 1 1 0 1
V3 1 0 1 0
  1. // 邻接矩阵(无向图)
  2. #include <stdio.h>
  3. #define n 4
  4. #define M 4
  5. #define N 4
  6. int main()
  7. {
  8. int i=0, j=0, k=0;
  9. int c;
  10. int Vertex[n];
  11. int a[M][N];
  12. printf("请输入顶点: ,以-1作为结束标志!\n");
  13. scanf("%d", &c);
  14. while( c != -1 )
  15. {
  16. Vertex[++i] = c;
  17. Vertex[i] = '\0';
  18. scanf("%d", &c);
  19. }
  20. printf("请输入顶点之间边的关系: 1表示两个顶点之间有边,0表示两个顶点之间无边。\n");
  21. for( i=0; i < M; i++ )
  22. {
  23. for( j=0; j < N; j++ )
  24. {
  25. printf("%d 和 %d 之间的关系为: ", i, j);
  26. scanf("%d", &a[i][j]);
  27. printf("%d\n", a[i][j]);
  28. }
  29. }
  30. printf("邻接矩阵(无向图)为: \n");
  31. for( i=0; i < M; i++ )
  32. {
  33. for( j=0; j < N; j++ )
  34. {
  35. printf("%d\t", a[i][j]);
  36. k++;
  37. }
  38. if( k%4 == 0 )
  39. {
  40. printf("\n");
  41. }
  42. }
  43. return 0;
  44. }

9.3.2 邻接矩阵(有向图)

9.3.3 邻接矩阵(网)

顶点数组: V0 V1 V2 V3
~ V0 V1 V2 V3
V0 0 18
V1 8 2
V2 4 0
V3 0

9.3.4 邻接表(无向图)

下标 data first
0 V0
1 V1
2 V2
3 V3
  1. // 邻接表(无向图)
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #define MAX_VERTEX_NUM 100
  5. typedef struct {
  6. int adjvex; //该边的另一个顶点的位置
  7. struct ArcNode *nextarc; //指向下一条边
  8. } ArcNode;
  9. typedef struct{
  10. int data; // 顶点的值
  11. ArcNode *firstarc; // 指向第一条依附该顶点的边的指针
  12. } VNode, AdjList[MAX_VERTEX_NUM];
  13. typedef struct{
  14. AdjList vertices; //顶点数组
  15. int vexnum, arcnum;
  16. } ALGraph;
  17. //定位函数
  18. int LocateVex(ALGraph G, int v)
  19. {
  20. int i=0;
  21. for( i=0; i < G.vexnum; i++ )
  22. {
  23. if( v == G.vertices[i].data )
  24. return i;
  25. }
  26. }
  27. void CreateUDG( ALGraph G )
  28. {
  29. ArcNode *p,*q;
  30. int i, j, k, v1, v2;
  31. printf("分别输入顶点个数和边的数目:\n");
  32. scanf("%d%d", &G.vexnum, &G.arcnum);
  33. printf("分别输入各个顶点值:\n");
  34. for( i=0; i < G.vexnum; i++ )
  35. {
  36. scanf("%d", &G.vertices[i].data);
  37. G.vertices[i].firstarc = NULL; //初始化
  38. }
  39. printf("分别输入各条边的两个顶点:\n");
  40. for( k=0; k < G.arcnum; k++ )
  41. {
  42. scanf("%d%d", &v1, &v2);
  43. //定位
  44. i = LocateVex(G,v1);
  45. j = LocateVex(G,v2);
  46. //申请一个结点
  47. p = (ArcNode*)malloc(sizeof(ArcNode));
  48. //赋值
  49. p->adjvex = j;
  50. p->nextarc = NULL;
  51. //连接结点
  52. p->nextarc = G.vertices[i].firstarc;
  53. G.vertices[i].firstarc = p;
  54. q = (ArcNode*)malloc(sizeof(ArcNode));
  55. q->adjvex = i;
  56. q->nextarc = NULL;
  57. q->nextarc = G.vertices[j].firstarc;
  58. G.vertices[j].firstarc = q;
  59. }
  60. }
  61. //输出邻接表
  62. void PrintUDG(ALGraph G)
  63. {
  64. int i, j;
  65. for( i=0; i < G.vexnum; i++ )
  66. {
  67. printf("%d:", i);
  68. ArcNode *p;
  69. p = G.vertices[i].firstarc;
  70. while( p != NULL )
  71. {
  72. printf("->%d", p->adjvex);
  73. p = p->nextarc;
  74. }
  75. printf("\n");
  76. }
  77. }
  78. int main()
  79. {
  80. ALGraph G;
  81. CreateUDG(G);
  82. PrintUDG(G);
  83. return 0;
  84. }

9.3.5 邻接表(有向图)

下标 data first
0 V0
1 V1
2 V2
3 V3

9.3.6 邻接表(网)

下标 data first
0 V0
1 V1
2 V2
3 V3

9.3.7 十字链表(有向图的优化)

data firstIn firstOut

9.3.8 邻接多重表(无向图的优化)

iVex iLink jVex jLink
下标 data first
0 V0
1 V1
2 V2
3 V3

9.3.9 边集数组

顶点数组: V0 V1 V2 V3
边数组 begin end weight
edges[0] 0 3 5
edges[1] 1 0 4
edges[2] 1 2 3
edges[3] 2 0 8
  1. // 边集数组
  2. #include <stdio.h>
  3. #define VertexNum 4
  4. #define EdgesNum 4
  5. int main()
  6. {
  7. int i=0, j=0, k=0, n=0, m=0;
  8. int c;
  9. int Vertex[VertexNum];
  10. int Begin[EdgesNum];
  11. int End[EdgesNum];
  12. int Weight[EdgesNum];
  13. // 存储顶点信息
  14. printf("请输入顶点: ,以-1作为结束标志!\n");
  15. scanf("%d", &c);
  16. while( c != -1 )
  17. {
  18. Vertex[++i] = c;
  19. Vertex[i] = '\0';
  20. scanf("%d", &c);
  21. }
  22. // 存储边的begin数值
  23. for( j=0; j < EdgesNum; j++ )
  24. {
  25. printf("请输入第 %d 条边的起点下标begin:\n", j);
  26. scanf("%d", &Begin[j]);
  27. }
  28. // 存储边的end数值
  29. for( k=0; k < EdgesNum; k++ )
  30. {
  31. printf("请输入第 %d 条边的终点下标end:\n", k);
  32. scanf("%d", &End[k]);
  33. }
  34. // 存储边的weight数值
  35. for( n=0; n < EdgesNum; n++ )
  36. {
  37. printf("请输入第 %d 条边的权值weight:\n", n);
  38. scanf("%d", &Weight[n]);
  39. }
  40. // 打印边集数组
  41. printf("边集数组信息为: 起点下标 终点下标 权值\n");
  42. for( m=0; m < EdgesNum; m++ )
  43. {
  44. printf("Edges[%d]\t%d\t %d\t %d\n", m, Begin[m], End[m], Weight[m]);
  45. }
  46. return 0;
  47. }

9.4 图的遍历

9.4.1 深度优先遍历

9.4.2 马踏棋盘算法(骑士周游问题)

  1. // 马踏棋盘算法
  2. #include <stdio.h>
  3. #include <time.h>
  4. #define X 8
  5. #define Y 8
  6. int chess[X][Y];
  7. //找到基于(x,y)位置的下一个可走的位置
  8. int nextxy(int *x, int *y, int count)
  9. {
  10. switch(count)
  11. {
  12. case 0:
  13. if( *x+2<=X-1 && *y-1>=0 && chess[*x+2][*y-1]==0 )
  14. {
  15. *x += 2;
  16. *y -= 1;
  17. return 1;
  18. }
  19. break;
  20. case 1:
  21. if( *x+2<=X-1 && *y+1<=Y-1 && chess[*x+2][*y+1]==0 )
  22. {
  23. *x += 2;
  24. *y += 1;
  25. return 1;
  26. }
  27. break;
  28. case 2:
  29. if( *x+1<=X-1 && *y-2>=0 && chess[*x+1][*y-2]==0 )
  30. {
  31. *x += 1;
  32. *y -= 2;
  33. return 1;
  34. }
  35. break;
  36. case 3:
  37. if( *x+1<=X-1 && *y+2<=Y-1 && chess[*x+1][*y+2]==0 )
  38. {
  39. *x += 1;
  40. *y += 2;
  41. return 1;
  42. }
  43. break;
  44. case 4:
  45. if( *x-2>=0 && *y-1>=0 && chess[*x-2][*y-1]==0 )
  46. {
  47. *x -= 2;
  48. *y -= 1;
  49. return 1;
  50. }
  51. break;
  52. case 5:
  53. if( *x-2>=0 && *y+1<=Y-1 && chess[*x-2][*y+1]==0 )
  54. {
  55. *x -= 2;
  56. *y += 1;
  57. return 1;
  58. }
  59. break;
  60. case 6:
  61. if( *x-1>=0 && *y-2>=0 && chess[*x-1][*y-2]==0 )
  62. {
  63. *x -= 1;
  64. *y -= 2;
  65. return 1;
  66. }
  67. break;
  68. case 7:
  69. if( *x-1>=0 && *y+2<=Y-1 && chess[*x-1][*y+2]==0 )
  70. {
  71. *x -= 1;
  72. *y += 2;
  73. return 1;
  74. }
  75. break;
  76. default:
  77. break;
  78. }
  79. return 0;
  80. }
  81. void print()
  82. {
  83. int i, j;
  84. for( i=0; i < X; i++ )
  85. {
  86. for( j=0; j < Y; j++ )
  87. {
  88. printf("%2d\t", chess[i][j]);
  89. }
  90. printf("\n");
  91. }
  92. printf("\n");
  93. }
  94. //深度优先遍历棋盘
  95. //(x,y)为位置坐标
  96. //tag是标记变量,每走一步,tag+1
  97. int TravelChessBoard(int x, int y, int tag)
  98. {
  99. int x1=x, y1=y, flag=0, count=0;
  100. chess[x][y] = tag;
  101. if( X*Y == tag )
  102. {
  103. //打印棋盘
  104. print();
  105. return 1;
  106. }
  107. //找到马的下一个可走的坐标(x1,y1),如果找到flag=1,否则为0
  108. flag = nextxy(&x1, &y1, count);
  109. while( 0==flag && count<7 )
  110. {
  111. count ++;
  112. flag = nextxy(&x1, &y1, count);
  113. }
  114. while( flag )
  115. {
  116. if( TravelChessBoard(x1, y1, tag+1) )
  117. {
  118. return 1;
  119. }
  120. //找到马的下一个可走的坐标(x1,y1),如果找到flag=1,否则为0
  121. x1 = x;
  122. y1 = y;
  123. count++;
  124. flag = nextxy(&x1, &y1, count);
  125. while( 0==flag && count<7 )
  126. {
  127. count ++;
  128. flag = nextxy(&x1, &y1, count);
  129. }
  130. }
  131. if( 0 == flag )
  132. {
  133. chess[x][y] = 0;
  134. }
  135. return 0;
  136. }
  137. int main()
  138. {
  139. int i, j;
  140. clock_t start, finish;
  141. start = clock();
  142. for( i=0; i < X; i++ )
  143. {
  144. for( j=0; j < Y; j++ )
  145. {
  146. chess[i][j] = 0;
  147. }
  148. }
  149. if( !TravelChessBoard(2, 0, 1) )
  150. {
  151. printf("抱歉,马踏棋盘失败了!\n");
  152. }
  153. finish = clock();
  154. printf("\n本次计算一共耗时: %f秒\n\n", (double)(finish-start)/CLOCKS_PER_SEC);
  155. return 0;
  156. }

9.4.3 广度优先遍历

9.5 构造最小生成树

9.5.1 普利姆(Prim)算法

~ V0 V1 V2 V3 V4 V5 V6 V7 V8
V0 0 10 11
V1 10 0 18 16 12
V2 18 0 22 8
V3 22 0 20 16 21
V4 20 0 26 7
V5 11 26 0 17
V6 16 17 0 19
V7 16 7 19 0
V8 12 8 21 0
  1. // Prim算法生成最小生成树
  2. void MiniSpanTree_Prim(MGraph G)
  3. {
  4. int min, i, j, k;
  5. int adjvex[MAXVEX]; // 保存相关顶点下标
  6. int lowcost[MAXVEX]; // 保存相关顶点间边的权值
  7. lowcost[0] = 0; // V0作为最小生成树的根开始遍历,权值为0
  8. adjvex[0] = 0; // V0第一个加入
  9. // 初始化操作
  10. for( i=0; i < G.numVertexes; i++ )
  11. {
  12. lowcost[i] = G.arc[0][i]; // 将邻接矩阵第0行所有权值先加入数组
  13. adjvex[i] = 0; // 初始化全部先为V0的下标
  14. }
  15. // 真正构造最小生成树的过程
  16. for( i=0; i < G.numVertexes; i++ )
  17. {
  18. min = INFINITY; // 初始化最小权值为65535等不可能数值
  19. j = 1;
  20. k = 0;
  21. // 遍历全部顶点
  22. while( j < G.numVertexes )
  23. {
  24. // 找出lowcost数组已存储的最小权值
  25. if( lowcost[j] != 0 && lowcost[j] < min )
  26. {
  27. min = lowcost[j];
  28. k = j; // 将发现的最小权值的下标存入k,以待使用
  29. }
  30. j++;
  31. }
  32. // 打印当前顶点边中权值最小的边
  33. printf("(%d, %d)", adjvex[k], k);
  34. lowcost[k] = 0; // 将当前顶点的权值设置为0,表示此顶点已经完成任务,进行下一个顶点的遍历
  35. // 邻接矩阵k行逐个遍历全部顶点
  36. for( j=1; j < G.numVertexes; j++ )
  37. {
  38. if( lowcost[j] != 0 && G.arc[k][j] < lowcost[j] )
  39. {
  40. lowcost[j] = G.arc[k][j];
  41. adjvex[j] = k;
  42. }
  43. }
  44. }
  45. }

9.5.2 克鲁斯卡尔(Kruskal)算法

~ begin end weight
edges[0] 4 7 7
edges[1] 2 8 8
edges[2] 0 1 10
edges[3] 0 5 11
edges[4] 1 8 12
edges[5] 3 7 16
edges[6] 1 6 16
edges[7] 5 6 17
edges[8] 1 2 18
edges[9] 6 7 19
edges[10] 3 4 20
edges[11] 3 8 21
edges[12] 2 3 22
edges[13] 3 6 24
  1. // Kruskal算法生成最小生成树
  2. int Find(int *parent, int f)
  3. {
  4. while( parent[f] > 0 )
  5. {
  6. f = parent[f];
  7. }
  8. return f;
  9. }
  10. void MiniSpanTree_Kruskal(MGraph G)
  11. {
  12. int i, n, m;
  13. Edge edges[MAGEDGE]; // 定义边集数组
  14. int parent[MAXVEX]; // 定义parent数组用来判断边与边是否形成环路
  15. for( i=0; i < G.numVertexes; i++ )
  16. {
  17. parent[i] = 0;
  18. }
  19. for( i=0; i < G.numEdges; i++ )
  20. {
  21. n = Find(parent, edges[i].begin);
  22. m = Find(parent, edges[i].end);
  23. if( n!= m ) // 如果n==m,不满足!
  24. {
  25. parent[n] = m; // 将此边的结尾顶点放入下标为起点的parent数组中,表示此顶点已经在生成树集合中
  26. printf("(%d, %d) %d ", edges[i].begin, edges[i].end, edges[i].weight);
  27. }
  28. }
  29. }

9.6 最短路径

9.6.1 迪杰斯特拉(Dijkstra)算法

~ V0 V1 V2 V3 V4 V5 V6 V7 V8
V0 0 1 5
V1 1 0 3 7 5
V2 5 3 0 1 7
V3 7 0 2 3
V4 5 1 2 0 3 6 9
V5 7 3 0 5
V6 3 6 0 2 7
V7 9 5 2 0 4
V8 7 4 0

D: 0 1 4 7 5 8 10 12 16
P: 0 0 1 4 2 4 3 6 7
final: 1 1 1 1 1 1 1 1 1

  1. // dijkstra算法求最短路径
  2. #define MAXVEX 9
  3. #define INFINITY 65535
  4. typedef int Patharc[MAXVEX]; // 用于存储最短路径下标的数组
  5. typedef int ShortPathTable[MAXVEX]; // 用于存储到各点最短路径的权值和
  6. void ShortestPath_Dijkstra(MGragh G, int V0, Patharc *P, ShortPathTable *D)
  7. {
  8. int v, w, k, min;
  9. int final[MAXVEX]; // final[w] = 1 表示已经求得顶点V0到Vw的最短路径
  10. // 初始化数据
  11. for( v=0; v < G.numVertexes; v++ )
  12. {
  13. final[v] = 0; // 全部顶点初始化为未找到最短路径
  14. (*D)[V] = G.arc[V0][v]; // 将与V0点有连线的顶点加上权值
  15. (*P)[V] = 0; // 初始化路径数组P为0
  16. }
  17. (*D)[V0] = 0; // V0至V0的路径为0
  18. final[V0] = 1; // V0至V0不需要路径
  19. // 开始主循环,每次求得V0到某个v顶点的最短路径
  20. for( v=1; v < G.numVertexes; v++ )
  21. {
  22. min = INFINITY;
  23. for( w=0; w < G.numVertexes; w++ )
  24. {
  25. if( !final[w] && (*D)[w] < min )
  26. {
  27. k = w;
  28. min = (*D)[w];
  29. }
  30. }
  31. final[k] = 1; // 将目前找到的最近的顶点置1
  32. for( w=0; w < G.numVertexes; w++ )
  33. {
  34. // 如果经过v顶点的路径比现在这条路径的长度短的话,更新
  35. if( !final[w] && (min+G.arc[k][w] < (*D)[w]) )
  36. {
  37. (*D)[w] = min + G.arc[k][w]; // 修改当前路径长度
  38. (*p)[w] = k; // 存放前驱顶点
  39. }
  40. }
  41. }
  42. }

9.6.2 弗洛伊德(Floyd)算法

  1. // 弗洛伊德算法求最短路径
  2. #define MAXVEX 9
  3. #define INFINITY 65535
  4. typedef int Pathmatirx[MAXVEX][MAXVEX];
  5. typedef int ShortPathTable[MAXVEX][MAXVEX];
  6. void ShortestPath_Floyd(MGraph G, Pathmatirx *P, ShortPathTable *D)
  7. {
  8. int v, w,k;
  9. // 初始化D和P
  10. for( v=0; v < G.numVertexes; v++ )
  11. {
  12. for( w=0; w < G.numVertexes; w++ )
  13. {
  14. (*D)[v][w] = G.matirx[v][w];
  15. (*P)[v][w] = w;
  16. }
  17. }
  18. // 优美的弗洛伊德算法
  19. for( k=0; k < G.numVertexes; k++ )
  20. {
  21. for( v=0; v < G.numVertexes; v++ )
  22. {
  23. if( (*D)[v][w] > (*D)[v][k] + (*D)[k][w] )
  24. {
  25. (*D)[v][w] = (*D)[v][k] + (*D)[k][w];
  26. (*P)[v][w] = (*P)[v][k];
  27. }
  28. }
  29. }
  30. }

9.7 拓扑排序

9.7.1 概念

9.7.2 拓扑排序算法

下标 in data first
0 0 C1
1 2 C2
2 2 C3
3 2 C4
4 1 C5
5 1 C6
6 3 C7
7 1 C8
8 1 C9
9 2 C10
10 1 C11
11 1 C12
12 0 C13
13 1 C14
14 1 C15
  1. // 拓扑排序算法
  2. // 边表结点声明
  3. typedef struct EdgeNode
  4. {
  5. int adjvex;
  6. struct EdgeNode *next;
  7. } EdgeNode;
  8. typedef struct VertexNode
  9. {
  10. int in; // 顶点入度
  11. int data;
  12. EdgeNode *firstedge;
  13. } VertexNode, AdjList[MAXVEX];
  14. typedef struct
  15. {
  16. AdjList adjList;
  17. int numVertexes, numEdges;
  18. } GraphAdjList, *GraphAdjList;
  19. // 拓扑排序算法
  20. // 若GL无回路,则输出拓扑排序序列并返回OK,否则返回ERROR
  21. Status TopologicalSort(GraphAdjList GL)
  22. {
  23. EdgeNode *e;
  24. int i, k, gettop;
  25. int top = 0; // 用于栈指针下标索引
  26. int count = 0; // 用于统计输出顶点的个数
  27. int *stack; // 用于存储入度为0的顶点
  28. stack = (int *)malloc(GL->numVertexes * sizeof(int));
  29. for( i=0; i < GL->numVertexes; i++ )
  30. {
  31. if( 0 == GL->adjList[i].in )
  32. {
  33. stack[++top] = i; // 将入度为0的顶点下标入栈
  34. }
  35. }
  36. while( 0 != top )
  37. {
  38. gettop = stack[top--]; // 出栈
  39. printf("%d -> ", GL->adjList[gettop].data);
  40. count++;
  41. for( e=GL->adjList[gettop].firstedge; e; e=e->next )
  42. {
  43. k = e->adjvex;
  44. // 注意:下边这个if条件是分析整个程序的要点
  45. // 将k号顶点邻接点的入度为-1,因为它的前驱已经消除
  46. // 接着判断-1后入度是否为0,如果为0则也入栈
  47. if( !(--GL->adjList[k].in) )
  48. {
  49. stack[++top] = k;
  50. }
  51. }
  52. }
  53. if( count < GL->numVertexes ) //如果count小于顶点数,说明存在环
  54. {
  55. return ERROR;
  56. }
  57. else
  58. {
  59. return OK;
  60. }
  61. }

9.8 关键路径

9.8.1 AOE网

9.8.2 几个关键词

顶点 C1 C2 C3 C4 C5 C6 C7 C8 C9
etv 0 6 4 5 7 7 14 12 16
ltv 0 6 6 6 7 8 14 12 16
a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11
ete 0 0 0 6 4 5 7 7 7 14 12
lte 0 0 2 6 6 6 7 7 8 14 12
下标 in data first
0 0 C1
1 1 C2
2 1 C3
3 1 C4
4 2 C5
5 1 C6
6 1 C7
7 2 C8
8 2 C9
  1. // 关键路径
  2. // 边表结点声明
  3. typedef struct EdgeNode
  4. {
  5. int adjvex;
  6. struct EdgeNode *next;
  7. } EdgeNode;
  8. // 顶点表结点声明
  9. typedef struct VertexNode
  10. {
  11. int in; // 顶点入度
  12. int data;
  13. EdgeNode *firstedge;
  14. } VertexNode, AdjList[MAXVEX];
  15. typedef struct
  16. {
  17. AdjList adjList;
  18. int numVertexes, numEdges;
  19. } GraphAdjList, *GraphAdjList;
  20. int *etv, *ltv;
  21. int *stack2; // 用于存储拓扑序列的栈
  22. int top2; // 用于stack2的栈顶指针
  23. // 拓扑排序算法
  24. // 若GL无回路,则输出拓扑排序序列并返回OK,否则返回ERROR
  25. Status TopologicalSort(GraphAdjList GL)
  26. {
  27. EdgeNode *e;
  28. int i, k, gettop;
  29. int top = 0; // 用于栈指针下标索引
  30. int count = 0; // 用于统计输出顶点的个数
  31. int *stack; // 用于存储入度为0的顶点
  32. stack = (int *)malloc(GL->numVertexes * sizeof(int));
  33. for( i=0; i < GL->numVertexes; i++ )
  34. {
  35. if( 0 == GL->adjList[i].in )
  36. {
  37. stack[++top] = i; // 将度为0的顶点下标入栈
  38. }
  39. }
  40. // 初始化etv都为0
  41. top2 = 0;
  42. etv = (int *)malloc(GL->numVertexes * sizeof(int));
  43. for( i=0; i < GL->numVertexes; i++ )
  44. {
  45. etv[i] = 0;
  46. }
  47. stack2 = (int *)malloc(GL->numVertexes * sizeof(int));
  48. while( 0 != top )
  49. {
  50. gettop = stack[top--]; // 出栈
  51. printf("%d -> ", GL->adjList[gettop].data);
  52. count++;
  53. for( e=GL->adjList[gettop].firstedge; e; e=e->next )
  54. {
  55. k = e->adjvex;
  56. // 注意:下边这个if条件是分析整个程序的要点
  57. // 将k号顶点邻接点的入度为-1,因为它的前驱已经消除
  58. // 接着判断-1后入度是否为0,如果为0则也入栈
  59. if( !(--GL->adjList[k].in) )
  60. {
  61. stack[++top] = k;
  62. }
  63. if( (etv[gettop] + e->weight) > etv[k] )
  64. {
  65. etv[k] = etv[gettop] + e->weight;
  66. }
  67. }
  68. }
  69. if( count < GL->numVertexes ) //如果count小于顶点数,说明存在环
  70. {
  71. return ERROR;
  72. }
  73. else
  74. {
  75. return OK;
  76. }
  77. }
  78. // 关键路径,GL为有向图,输出GL的各项关键活动
  79. void CriticalPath(GraphAdjList GL)
  80. {
  81. EdgeNode *e;
  82. int i, gettop, k, j;
  83. int ete, lte;
  84. // 调用改进后的拓扑排序,求出etv和stack2的值
  85. TopologicalSort(GL);
  86. // 初始化ltv都为汇点的时间
  87. ltv = (int *)malloc(GL->numVertexes * sizeof(int));
  88. for( i=0; i < GL->numVertexes; i++ )
  89. {
  90. ltv[i] = etv[GL->numVertexes - 1];
  91. }
  92. // 从汇点倒过来逐个计算ltv
  93. while( 0 != top2 )
  94. {
  95. gettop = stack2[top2--]; // 注意,第一个出栈是汇点
  96. for( e=GL->adjList[gettop].firstedge; e; e=e->next )
  97. {
  98. k = e->adjvex;
  99. if( ltv[k] - e->weight < ltv[gettop] )
  100. {
  101. ltv[gettop] = ltv[k] - e->weight;
  102. }
  103. }
  104. }
  105. // 通过etv和ltv求ete和lte
  106. for( j=0; j < Gl->numVertexes; j++ )
  107. {
  108. for( e=GL->adjList[j].firstedge; e; e=e->next )
  109. {
  110. k = e->adjvex;
  111. ete = etv[j];
  112. lte = ltv[k] - e->weight;
  113. if( ete == lte )
  114. {
  115. printf("<v%d, v%d> length: %d, ", GL->adjList[j].data, GL->adjList[k].data, e->weight);
  116. }
  117. }
  118. }
  119. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注