【动画】有向无环图:拓扑排序、关键路径

注:学习自

严蔚敏《数据结构》
李春葆《数据结构》


一丶了解AOE

AOE(Activity On Edge)网:用来估算完成事件时间

顶点表示事件,边表示活动,权表示活动持续时间。是一个带权的有向无环图
在这里插入图片描述

如图,学习完计算机基础到开始学习数据结构需要2天,学习完计算机基础到开始学习计算机原理需要20天,后面同理,可以看出学到操作系统必须30天。


二丶AOE 与 关键路径

有向图是描述一项工程或系统的进行过程的有效工具,几乎所有的工程都可以分为若干个子工程,而这些子工程之间,通常受着一定约束,比如事件先后约束,每个活动完成的时间

人们在做工程时关注两个问题
  • 一是工程是否能顺利进行,就是从AOE网中使用拓扑排序,检测出图中是否有环,没有环的话可以依照得到的序列去完成该项目,比如软件工程学习课程可以按照 计算机基础,数据结构,计算机原理,操作系统来学
为什么有环就不能顺利进行呢?
大家可以思考就像下面的例子我们应该从何处开始呢?是蛋吗?那必须要有母鸡 ; 是雏鸡吗?那必须要有蛋 ; 是母鸡吗?那必须要有雏鸡。显然,这里的每项活动都是以自己为先决条件,这是不可能的,无从下手,死循环
在这里插入图片描述
  • 二是工程必须最短时间完成,从AOE网中使用关键路径,可以看出事件完成时间,比如软件工程学习课程关键路径是,计算机基础,计算机原理,操作系统,这花费30天。分析关键路径我们可以提高关键活动的工效,缩短整个周期,从计算机基础到计算机原理时间太长了,肯定是去玩了,假如不玩,就直接缩短到3天,整个学习过程可以只用13天完成。所以得到关键路径就是为了分析是否可以虽短从而缩短工期

三丶拓扑排序:工程是否能顺利进行

拓扑排序就是从一个有向图中找到一个拓扑序列的过程。找到了拓扑序列也就是拓扑排序完成,工程可以顺利进行

什么是拓扑序列,以及怎么找到
图中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前(注<u,v>与<v,u>不是同一条边)。就如下图中,<1,2> < 3 ,2> 2事件必须出现在1事件与3事件之前,只有完成了1事件与3事件才能进行2事件,有先后次序
在这里插入图片描述
图中的边有 <1,2> 、<3,2> 、<2,5>、<3,4>、 <4,5> 、<2,6> 、<3,6>
我们就开始进行排序:132645 ,134265,132456……很多都是拓扑序列
这样凌乱的猜想是不能忍受的,我们需要找到一个规范的算法去寻找拓扑序列,如下
由AOV网构造拓扑序列的拓扑排序算法主要是 循环执行以下两步直到不存在入度为0的顶点为止
(1) 选择一个入度为0的顶点并输出之;
(2) 从网中删除此顶点及所有出边。
循环结束后,若输出的顶点数小于网中的顶点数,则说明AVO网有回路,否则输出的顶点序列就是一种拓扑序列。这里得到的排序并不是唯一的
Status TopologicalSort(ALGraph G) {  // 算法7.12
  // 有向图G采用邻接表存储结构。
  // 若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则ERROR。
  SqStack S;
  int count,k,i;
  ArcNode *p;
  char indegree[MAX_VERTEX_NUM];
  FindInDegree(G, indegree);   // 对各顶点求入度indegree[0..vernum-1]
  InitStack(S);
  for (i=0; i<G.vexnum; ++i)       // 建零入度顶点栈S
    if (!indegree[i]) Push(S, i);  // 入度为0者进栈
  count = 0;                       // 对输出顶点计数
  while (!StackEmpty(S)) {
    Pop(S, i); 
    printf(i, G.vertices[i].data);  ++count;  // 输出i号顶点并计数
    for (p=G.vertices[i].firstarc;  p;  p=p->nextarc) {
      k = p->adjvex;               // 对i号顶点的每个邻接点的入度减1
      if (!(--indegree[k])) Push(S, k);  // 若入度减为0,则入栈
    }
  }
  if (count<G.vexnum) return ERROR;      // 该有向图有回路
  else return OK;
} // TopologicalSort

注:对于你拓扑序列,就是DFS函数最先出栈的顶点即为出度为0的顶点,是拓扑序列的最后一个顶点,由此按照DFS出栈的顺序记录就是逆拓扑序列

四丶关键路径:工程必须最短时间完成

在这里插入图片描述

AOE网中的有些活动是可以并行的进行,所以完成工程的最短时间请添加图片描述
点最长路径的长度,对你没有看错,最长路径是最短时间,所以找关键路径就是找到最长路径所经过的点不难看出, 1 - 2 - 5是关键路径,关键路径长度为14天。

肉眼的观察不能忍受的,我们需要找到一个规范的算法去寻找关键路径,如下
在这里插入图片描述
举例

在这里插入图片描述
在这里插入图片描述

实现
Status TopologicalSort_Modify(ALGraph G, Stack &T) {  // 算法7.13
  // 有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve(全局变量)。
  // T为拓扑序列定点栈,S为零入度顶点栈。
  // 若G无回路,则用栈T返回G的一个拓扑序列,且函数值为OK,否则为ERROR。
  Stack S;int count=0,k;
  char indegree[40];
  ArcNode *p;
  InitStack(S);
  FindInDegree(G, indegree);  // 对各顶点求入度indegree[0..vernum-1]
  for (int j=0; j<G.vexnum; ++j)     // 建零入度顶点栈S
    if (indegree[j]==0) Push(S, j);  // 入度为0者进栈
  InitStack(T);//建拓扑序列顶点栈T
  count = 0;  
  for(int i=0; i<G.vexnum; i++) ve[i] = 0;  // 初始化
  while (!StackEmpty(S)) {
    Pop(S, j);  Push(T, j);  ++count;       // j号顶点入T栈并计数
    for (p=G.vertices[j].firstarc;  p;  p=p->nextarc) {
      k = p->adjvex;            // 对j号顶点的每个邻接点的入度减1
      if (--indegree[k] == 0) Push(S, k);   // 若入度减为0,则入栈
      if (ve[j]+p->info > ve[k])  ve[k] = ve[j]+p->info;
    }//for  *(p->info)=dut(<j,k>)
  }//while
  if (count<G.vexnum) return ERROR;  // 该有向网有回路
  else return OK;
} // TopologicalOrder

Status CriticalPath(ALGraph G) { 
  // G为有向网,输出G的各项关键活动。
  Stack T;
  int a,j,k,el,ee,dut;
  char tag;
  ArcNode *p;
  if (!TopologicalSort_Modify(G, T)) return ERROR; //用拓扑排序检测有无环
  for(a=0; a<G.vexnum; a++)
    vl[a] = ve[G.vexnum-1];    // 初始化顶点事件的最迟发生时间
  while (!StackEmpty(T))       // 按拓扑逆序求各顶点的vl值
    for (Pop(T, j), p=G.vertices[j].firstarc;  p;  p=p->nextarc) {
      k=p->adjvex;  dut=p->info;     //dut<j,k>
      if (vl[k]-dut < vl[j]) vl[j] = vl[k]-dut;
    }
  for (j=0; j<G.vexnum; ++j)            // 求ee,el和关键活动
    for (p=G.vertices[j].firstarc;  p;  p=p->nextarc) {
      k=p->adjvex;dut=p->info;   
      ee = ve[j];  el = vl[k]-dut;
      tag = (ee==el) ? '*' : ' ';
      printf(j, k, dut, ee, el, tag);   // 输出关键活动
    }
  return OK;
} // CriticalPath

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yilyil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值