数据结构24————图的拓扑排序和关键排序

本文详细介绍了图的拓扑排序和关键路径算法,包括AOV网和AOE网的概念,以及如何通过算法确定活动之间的优先级关系和找到关键路径。提供了算法的具体实现代码。

数据结构21————图的拓扑排序和关键排序

一. 目录

二. 图的拓扑排序

1. 算法定义

AOV网

在一个表示工程的有向图中,用顶点表示活动之间优先级关系,这样的有向图为顶点表示活动的网,我们称为AOV网

拓扑排序

按照有向图给出的次序关系,将图中的顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称为拓扑有序序列

2. 算法思路
  1. 从有向图中选取一个没有前驱的顶点,并输出之
  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. 算法思路
  1. “事件vj”的最早发生时间ve(j):
    从源点到顶点j的最长路径长度,表示从源点到顶点j所以路径的活动均已完成,vj才能发生。

可按拓扑序列求ve(j)
ve(0)=0
ve(j)=MAX(ve(t)+ < t,j>的权值)

  1. "事件vk"的最晚发生事件vl(k):
    在汇点最早发生事件不变的前提下,事件vk发生的最晚事件。即不延迟整个工期的情况下,vk最迟必须发生的时间

可按拓扑逆序求vl(j)
vl(n-1)=ve(n-1);
vl(t)=MIN{vl(j)-< t,j>的权值}

  1. 活动i的最早开始时间e(i):
    若活动i对应弧< j,k>,则E(i)等于事件j的最早发生时间。即活动i的前驱活动全部结束,活动i才能开始

即e(i)=ve(j)

  1. 活动i的最晚开始时间l(i)
    若活动i对应弧< j,k>,则l(i)等于事件k最迟发生事件减去活动(i)持续的时间

l(i)=vl(k)-< j,k>的权值

关键路径的求解思路为:

  1. 求每个事件的最早发生事件ve(j);
  2. 求每个事件的最晚发生事件vl(k);
  3. 求每个活动的最早发生事件e(i);
  4. 求每个红的的最晚发生事件l(i)
  5. 找出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); 
			}
		}			
	}
	 
}

这里写图片描述

四. 源码地址

点此查看源码

五. 参考资料

《大话数据结构》
《数据结构与算法》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值