数据结构-----图的拓扑排序和关键路径算法
部分图片取自:http://www.cnblogs.com/navorse/articles/1893863.html
在介绍拓扑排序和关键路径之前,先引入AOE网络的概念:
该图为一个AOE网,顶点表示事件,如v1,v2,v3...。弧表示活动,如a1,a2,a3...,而每一条边表示的值为完成该活动所需的时间。
比如上图中,完成活动a1需要6个单位的时间,完成活动a3需要5个单位的时间。
AOE网络是一个加权有向图,即每一条边都是带方向且带有权值的。对于一个有向边,箭头指向的点为终点,另一个点则是起点。
顶点的入度是指所有以该顶点为终点的有向边的个数。如上图中以顶点v5为终点的有向边为a4和a5,所以顶点v5的入度为2。
顶点的出度是指所有以该顶点为起点的有向边的个数。如上图中以顶点v1为起点的有向边为a1,a2和a3,所以顶点v1的出度为3。
我们把入度为0的顶点叫做源点,出度为0的顶点叫做汇点。上图中v1是源点,v9是汇点。
可以理解为从源点出发,虽然中间会有很多不同的分岔口,但最终都会到达汇点。一个AOE网络至少包含一个源点和一个汇点。
概念说完了,接下来讨论一下AOE网络的性质:
对于AOE网络中的某一个顶点(事件)来说,只有当所有以该顶点为终点的有向边(活动)都完成后,该顶点代表的事件才能够发生。
同时只有某一个顶点(事件)发生后,以该顶点为起点的有向边(活动)才能够开始。
对于图中的顶点(事件)v5来说,只有边(活动)a4和a5完成后,事件v5才可以发生,边(活动)a7和a8才能开始。
一个AOE网络很形象的描述了在一个大的工程中的每一个子工程的前驱工程是什么,以及其后续工程是什么。同时根据每一个活动(边)的权值,我们可以知道某一事件发生的时间是什么。
接下来说一下拓扑排序,实现拓扑排序的步骤如下:
步骤1:找到AOE网络中入度为0的顶点,输出它。如果找不到,停止排序。
步骤2:删除所有与该点关联的边,重复步骤1。
步骤3:如果输出顶点个数小于总顶点个数,则证明图中存在环,没有关键路径
拓扑排序的结果叫做拓扑序列,一个AOE网络的拓扑序列不止一种
接下来讨论关键路径,先明确几个名词。
关键路径:从源点到汇点的路径长度最大的路径叫关键路径。
事件的最早发生时间ve:因为对于某一个事件(顶点)来说,其入度可能大于1,所以从源点到达该顶点的路就不止一条。对于其中一条路来说,经过的所有边的权值的和就是对这条路来说,到达该顶点需要的时间。把到达该顶点所有路的时间进行比较,取最大值,就是该事件的最早发生时间。
事件的最迟发生时间vl:值在不耽误整个工程完成时间的前提下,某一事件最晚的发生时间。这个通常比较难理解,举个例子说明一下。
比如说有三个事件a,b,c。a和b是c的前驱事件,完成活动ac需要的时间是2小时,完成活动bc需要的时间是3小时。假设现在时间是下午1点,此时事件a和事件b都已经发生,根据前面的描述可知,活动ac和bc都可以开始了。但是因为bc需要完成的时间长,所以事件c发生的时间是下午4点。那么因为ac只需两个小时就可以完成,那么事件a发生的时间可以是下午2点,再加上ac完成时间2个小时也是下午4点,并没有耽误到事件c的发生,这就是所谓的最晚发生时间。所以事件a的最早发生时间是下午1点,最晚发生时间是下午2两点。
活动开始的最早时间e:因为事件发生的同时与该事件关联的活动也就可以开始。所以一个活动(边)的最早开始时间和其起点所代表的事件的最早开始时间相同。
活动开始的最晚时间l:事件的最晚发生时间是将事件推迟,活动的最晚开始时间是将活动推迟,二者类似。
关键活动:e和l相等的活动称为关键活动。
所以求关键路径的问题就是求所有关键活动的问题。
示例如下:
接下来就是拓扑排序和关键路径的实现了。
首先需要考虑的是AOE网络的存储,需要一个图的类,可以用邻接表的方式实现。
它存在一个公有函数eraseEdge(int v1, int v2),可以删除边<v1,v2>。
一个公有函数inDegree(int v),返回顶点v的入度。
一个公有函数getFirstNode(int v),返回与顶点v关联的边的邻接表的表头指针。
其次需要考虑用什么存储拓扑序列,考虑到在求拓扑序列时汇点是最后一个被存储,而最晚发生时间是从后向前求得,汇点应该首先被弹出,所以选用栈来存储。
同时保存入度为0的顶点时也可以用栈来存储,不同的存储方式得出的序列不同(拓扑序列不止一个)。
最后需要两个数组,一个存储事件的最早发生时间,一个存储事件的最晚发生时间。
#define MAX_VEX 10
linearStack<int> stack2;bool TopologicalSort(linkedWDigigraph theGraph, int *pEtv)
{linearStack<int> stack1;for(int i = 0; i<=MAX_VEX; ++i) //初始化最早发生时间pEtv[i] = 0;for(int i = 1; i<=MAX_VEX; ++i){if(theGraph.inDegree(i) == 0) //首先寻找入度为0的顶点stack1.push(i);}int v1;int nCnt(0);chainNode<int>* pNode;while(!(stack1.empty())){v1 = stack1.top();stack1.pop();stack2.push(v1); //保存拓扑序列if(++nCnt == MAX_VEX) //判断是否有环break;pNode = theGraph.getFirstNode(v1);int v2, weight;while(pNode != NULL){v2 = pNode->element;weight = pNode->weight;pNode = pNode->next;theGraph.eraseEdge(v1, v2);if(theGraph.inDegree(v2) == 0) //删除和顶点v1关联的边,再次寻找入度为0的顶点stack1.push(v1);if(pEtv[v2] < weight + pEtv[v1]) //更新最大值pEtv[v2] = weight + pEtv[v1];}}return nCnt == MAX_VEX; //判断是否有环
}
stack2存储着拓扑序列,供关键路径函数使用:
void CriticalPath(linkedWDigraph& theGraph, int *pEtv, int *pLtv)
{for(int i = 1; i<=MAX_VEX; ++i)pLtv[i] = pEtv[MAX_VEX]; //初始化最晚发生时间int v1;chainNode<int>* pNode = NULL;while(!(stack2.empty())){v1 = stack2.top();stack2.pop();pNode = theGraph.getFirstNode(v1);int v2;while(pNode != NULL){v2 = pNode->element;if(lEtv[v1] > lEtv[v2] - pNode->weight) //更新最晚发生时间lEtv[v1] = lEv[v2] - pNode->weight;pNode = pNode->next;}}int ete(0);int lte(0);for(int i= 1; <= MAX_VEX; ++i){pNode = theGraph.getFirstNode(i);while(pNode != NULL){ete = pEtv[i];lte = pLtv[pNode->element] - pNode->weight;if(ete == lte) //判断最早发生时间和最晚发生时间是否相等{cout << "<v" << i << ",v" << pNode->element << "> :" << pNode->weight << endl;}pNode = pNode->next;}}
}
数据结构-----图的拓扑排序和关键路径算法相关推荐
- BUCT数据结构——图(拓扑排序、关键路径)
文章目录 问题 A: 邻接矩阵存储的图,节点的出度和入度计算(附加代码模式) 问题 B: 算法7-12:有向无环图的拓扑排序 问题 C: 有向图是否存在环? 问题 D: 图-节点的最早发生时间 问题 ...
- 大话数据结构 第七章 图(二) 最小生成树、最短路径、拓扑排序、关键路径算法
大话数据结构 第七章 图(二) 最小生成树.最短路径.拓扑排序.关键路径算法 最小生成树 定义 Prim算法 Kruskal算法 最短路径 Dijkstra算法 Floyd算法 拓扑排序 AOV网 拓 ...
- 拓扑排序和关键路径课程设计
目录 1. 设计任务书... 3 1.1设计任务... 3 1.2程序功能... 3 1.3运行环境... 3 2. 本组课题... 3 2.1课题... 3 2.2本人任务... 3 3 ...
- 考研复习之数据结构笔记(十二)图(下)(图的应用,包含最小生成树、最短路径、拓扑排序、关键路径以及单元小结)
目录 一.图的应用 1.1 最小生成树 (1)基本概念与问题引入 (2)Prim(普里姆)算法 (3)Kruskal(克鲁斯卡尔)算法 1.2 最短路径 (1)基本概念与问题引入 (2)Dijkstr ...
- 数据结构与算法之-----图(拓扑排序)
[ 写在前面的话:本专栏的主要内容:数据结构与算法. 1.对于初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据 ...
- C语言数据结构与算法---拓扑排序、关键路径
文章目录 一. 有向无环图 二. 拓扑排序 1. 分析 2. 拓扑排序的定义及方法 3. 拓扑排序的重要应用 4. 拓扑排序的算法实现 三. 关键路径 1.分析 2. 什么是关键路径 3. 关键路径的 ...
- 拓扑排序和关键路径的图形化显示
资源下载地址:https://download.csdn.net/download/sheziqiong/85883662 资源下载地址:https://download.csdn.net/downl ...
- 图论算法—图的拓扑排序介绍和Kahn算法原理解析以及Java代码的实现
详细介绍了图的拓扑排序的概念,然后介绍了求拓扑序列的算法:Kahn算法的原理,最后提供了基于邻接矩阵和邻接表的图对该算法的Java实现. 阅读本文需要一定的图的基础,如果对于图不是太明白的可以看看这篇 ...
- 数据结构-考研难点代码突破 (C++实现有向无环图的拓扑排序)
文章目录 1. AOV网 2. 拓扑排序 C++代码 1. AOV网 AOV网∶若用DAG 图(有向无环图)表示一个工程,其顶点表示活动,用有向边<Vi,Vj>表示活动 Vi必须先于活动V ...
最新文章
- 大数据安全“脆弱性”凸显 防护成重要课题
- 黄煦涛教授逝世:获誉华人AI视觉鼻祖、一代宗师,完美家庭楷模
- 怎样解决xcode里开发cocos2dx改动lua脚本后不刷新的问题
- 【数字信号处理】相关函数 ( 自相关函数示例 )
- dj打碟怎么学_南京学DJ打碟
- 用自己的数据集在R-FCN框架下进行检测
- getInvokeArg()和setParam配合使用
- Spring Enable*高级应用及原理
- 为何获得风险投资的公司多数倒闭了?
- 服务器操作系统使用相关要求,服务器操作系统使用相关要求
- matlab求解联名方程组带三角函数的,matlab三角函数方程组
- uc android flash插件,Android版UC浏览器7.3发布 支持Flash元素
- 山东高速资产注入承诺何时兑现 期待画饼成真
- 数独的Java版解法
- 网管的自我修养-电脑维护
- 部分国产水文水动力模型介绍
- 【观察】亚信科技:“三新”收入再翻番背后,是全栈数智化能力的释放
- 循环 — 你必须要会的十五道编程题
- JS实现Excel导入以及table导出为Excel
- ClassFinal对项目进行加密处理
热门文章
- 台式电脑怎么连接手机热点_电脑搜不到手机热点 为什么搜不到手机热点
- Java黑皮书课后题第6章:**6.26(回文素数)回文素数是指一个数同时为素数和回文数。编程程序,显示前100个回文素数,每行显示10个数,数字中间用一个空格隔开
- dell服务器sd卡装系统,DELL服务器通过sd卡安装系统(iDRACUsevFlash).doc
- c语言fmt,Go 标准库-fmt
- [转载]线上应用故障排查之一:高CPU占用
- 第八周结对编程四则运算二
- Java往事之《返回整数的长度》
- UIActionSheet
- Android fastjson
- 在线网摘收藏?让Google来吧!