数据结构21————图的拓扑排序和关键排序
一. 目录
文章目录
二. 图的拓扑排序
1. 算法定义
AOV网
在一个表示工程的有向图中,用顶点表示活动之间优先级关系,这样的有向图为顶点表示活动的网,我们称为AOV网
拓扑排序
按照有向图给出的次序关系,将图中的顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称为拓扑有序序列
2. 算法思路
- 从有向图中选取一个没有前驱的顶点,并输出之
- 从有向图中删去此项顶点及其所有以它为尾的弧
重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
3. 算法演示
4. 算法代码
void TopologicalSort(AdjList *GL){
ArcNode *arc;
int i,k,gettop;
int top=0; //栈顶
int count=0; //用于统计顶点的个数
int stack[MAXVEX];
for(i=0;i<GL->vexnum;i++){
if(GL->vertex[i].in==0){
stack[++top]=i;
}
}
while(top!=0){
gettop = stack[top--]; //出栈
printf("%c->",GL->vertex[gettop].vexdata);
count++; //统计输出的节点个数
for(arc=GL->vertex[gettop].head;arc;arc=arc->next){ //对此顶点弧表遍历
k=arc->adhVex;
if(!(--GL->vertex[k].in)){ //将k顶点的邻接点度-1
stack[++top]=k; //如果度减为0,则入栈
}
}
}
if(count < GL->vexnum) //表示有回路
return 1;
else
return 0;
}
三. 图的关键路径
1. 算法定义
AOE网
在有向图中,用顶点表示事件,用弧表示活动,弧的权值表示活动所用的时间。我们称这种有向图为AOE网
源点
存在唯一的,入度为0的顶点,叫源点
汇点
存在唯一的,出度为0的顶点,叫汇点
关键路径
从源点到汇点的最长带权路径长度即完成整个工程任务所需的时间,该路径称为关键路径。
关键活动
关键路径上的活动叫做关键活动。关键活动的权值增加(活动延期),将使AOE-网的最长路径长度增加(整个活动延期)
2. 算法思路
- “事件vj”的最早发生时间ve(j):
从源点到顶点j的最长路径长度,表示从源点到顶点j所以路径的活动均已完成,vj才能发生。
可按拓扑序列求ve(j)
ve(0)=0
ve(j)=MAX(ve(t)+ < t,j>的权值)
- "事件vk"的最晚发生事件vl(k):
在汇点最早发生事件不变的前提下,事件vk发生的最晚事件。即不延迟整个工期的情况下,vk最迟必须发生的时间
可按拓扑逆序求vl(j)
vl(n-1)=ve(n-1);
vl(t)=MIN{vl(j)-< t,j>的权值}
- 活动i的最早开始时间e(i):
若活动i对应弧< j,k>,则E(i)等于事件j的最早发生时间。即活动i的前驱活动全部结束,活动i才能开始
即e(i)=ve(j)
- 活动i的最晚开始时间l(i)
若活动i对应弧< j,k>,则l(i)等于事件k最迟发生事件减去活动(i)持续的时间
l(i)=vl(k)-< j,k>的权值
关键路径的求解思路为:
- 求每个事件的最早发生事件ve(j);
- 求每个事件的最晚发生事件vl(k);
- 求每个活动的最早发生事件e(i);
- 求每个红的的最晚发生事件l(i)
- 找出e(i)=l(i)的活动ai,即为关键活动
3. 算法演示
4. 算法代码
修改后拓扑排序
int ve[MAXVEX],vl[MAXVEX];//事件的最早发生时间和最迟发生时间
int stack2[MAXVEX]; //用于存储拓扑排序的栈
int top2; //stack的栈顶指针
void TopologicalSort(AdjList *GL){
ArcNode *arc;
int i,k,gettop;
int top=0; //栈顶
int count=0; //用于统计顶点的个数
int stack[MAXVEX];
for(i=0;i<GL->vexnum;i++){
if(GL->vertex[i].in==0){
stack[++top]=i;
}
}
while(top!=0){
gettop = stack[top--]; //出栈
count++; //统计输出的节点个数
stack2[++top2]=gettop;//将弹出的顶点序列压入拓扑排序的栈中
for(arc=GL->vertex[gettop].head;arc;arc=arc->next){ //对此顶点弧表遍历
k=arc->adhVex;
if(!(--GL->vertex[k].in)){ //将k顶点的邻接点度-1
stack[++top]=k; //如果度减为0,则入栈
}
if((ve[gettop]+arc->weight >ve[k])){ //求各顶点的最早发生时间
ve[k] = ve[gettop]+arc->weight;
}
}
}
if(count < GL->vexnum) //表示有回路
return 1;
else
return 0;
}
关键路径算法
void CriticalPath(AdjList *GL){
ArcNode *arc;
int i,gettop,k,j;
int e,l; // 活动的最早和最晚发生时间
TopologicalSort(GL); //求拓扑排序,计算数组ve和stack2的值
for(i=0;i<GL->vexnum;i++){
vl[i]=ve[GL->vexnum-1];
}
while(top2!=0){
gettop = stack2[top2--];
for(arc = GL->vertex[gettop].head;arc;arc=arc->next){
//求各顶点的最迟发生时间vl值
k=arc->adhVex;
if(vl[k]-arc->weight <vl[gettop]){
vl[gettop]=vl[k]-arc->weight;
}
}
}
for(j=0;j<GL->vexnum;j++){ //求活动的e,l和关键活动
for(arc = GL->vertex[j].head;arc;arc=arc->next){
k=arc->adhVex;
e=ve[j];
l=vl[k]-arc->weight;
if(e==l){ //两者相等即为关键活动
printf("<%c,%c> lenghth:%d\n",GL->vertex[j].vexdata,GL->vertex[k].vexdata,arc->weight);
}
}
}
}
四. 源码地址
五. 参考资料
《大话数据结构》
《数据结构与算法》