数据结构学习:图的拓扑排序和AOV网

数据结构学习:图的拓扑排序和AOV网
AOV⽹(Activity On Vertex NetWork,⽤顶点表示活动的⽹):
⽤DAG图(有向⽆环图)表示⼀个⼯程。顶点表示活动,有向边<Vi , Vj >表示活动Vi 必须先于活动Vj 进⾏

拓扑排序:在图论中,由⼀个有向⽆环图的顶点组成的序列,当且仅当满⾜下列条件时,称为该图的⼀个拓扑排序:
① 每个顶点出现且只出现⼀次。
② 若顶点A在序列中排在顶点B的前⾯,则在图中不存在从顶点B到顶点A的路径。

或定义为:拓扑排序是对有向⽆环图的顶点的⼀种排序,它使得若存在⼀条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后⾯。每个AOV⽹都有⼀个或多个拓扑排序序列。

拓扑排序的实现:
① 从AOV⽹中选择⼀个没有前驱(⼊度为0)的顶点并输出。
② 从⽹中删除该顶点和所有以它为起点的有向边。
③ 重复①和②直到当前的AOV⽹为空或当前⽹中不存在⽆前驱的顶点为⽌。

#define MaxvertexNum 100
//图中顶点数目的最大值
typedef struct ArcNode		//边表结点
{
	int adjvex;				//该弧所指向的顶点的位置
	struct ArcNode *nextarc;//指向下一条弧的指针
}ArcNode;

typedef struct vNode	//顶点表结点
{
	vertexType data;	//顶点信息
	ArcNode * firstarc;	//指向第一条依附该顶点的弧的指针
}VNode,AdjList [ MaxVertexNum ];

typedef struct
{
	AdjList vertices;	//邻接表
	int vexnum, arcnum;	//图的顶点数和弧数
}Graph;					// Graph是以邻接表存储的图类型


bool Topologicalsort ( Graph G)
{
	Initstack( S );		//初始化栈,存储入度为0的顶点

	for (int i=0 ;i<G.vexnum; i++)
		if ( indegree[ i]==0 )
			Push(s,i);		//将所有入度为0的顶点进栈
	int count=0;			//计数,记录当前已经输出的顶点数
	while( ! IsEmpty (S)) 	//栈不空,则存在入度为o的顶点
	{
		Pop ( s,i );		//栈顶元素出栈
		print [count++] = i;//输出顶点
		for ( p = G.vertices[i].firstarc;p;p = p->nextarc ) 
		{
			//将所有i指向的顶点的入度减1,并且将入度减为o的顶点压入栈s
			v=p->adjvex;
			if( !( --indegree[v]))//自减之后为0
				Push(s,v);//入度为0,则入栈
		}
	}// while
	if ( count<G.vexnum)
	return false;		//排序失败,有向图中有回路

	else
		return true ;	//拓扑排序成功
}

时间复杂度:O(|V|+|E|)
若采⽤邻接矩阵,则需O(|V|^2 )
在这里插入图片描述

对⼀个AOV⽹,如果采⽤下列步骤进⾏排序,则称之为逆拓扑排序:
① 从AOV⽹中选择⼀个没有后继(出度为0)的顶点并输出。
② 从⽹中删除该顶点和所有以它为终点的有向边。
③ 重复①和②直到当前的AOV⽹为空。

拓扑排序是从头到尾
逆拓扑排序是从尾到头

// 逆拓扑排序
void DFSTraverse(Graph G)	//对图G进行深度优先遍历
{
	for(v=;v<G.vexnum;++v)
		visited[v]=FALSE;	//初始化已访问标记数据
	for( v=; v<G.vexnum;++v)//本代码中是从v=0开始遍历
		if ( !visited[v])
			DFS(G,v);
}
void DFS(Graph G,int v)		//从顶点v出发,深度优先遍历图G
{

	visit(v);
	//访问顶点v
	visited[v]=TRUE;	//设已访问标记
	
	for(w = FirstNeighbor(G,v);w >= 0;w = NextNeighor(G,v,w))
		if( !visited [w] )	//w为u的尚未访问的邻接顶点
		{
			DFS(G,w);
		}
	// print(v);	输出顶点v,在顶点退栈前输出
}

通过栈,将先前遍历的结点存储到栈里,知道所有结点遍历完,然后从栈中取出

AOE网
在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为⽤边表示活动的⽹络,简称AOE⽹

AOE⽹具有以下两个性质:
① 只有在某顶点所代表的事件发⽣后,从该顶点出发的各有向边所代表的活动才能开始;
② 只有在进⼊某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发⽣。另外,有些活动是可以并⾏进⾏的

在AOE⽹中仅有⼀个⼊度为0的顶点,称为开始顶点(源点),它表示整个⼯程的开始;
也仅有⼀个出度为0的顶点,称为结束顶点(汇点),它表示整个⼯程的结束。

从源点到汇点的有向路径可能有多条,所有路径中,具有最⼤路径⻓度的路径(权值而非结点数)称为关键路径,⽽把关键路径上的活动称为关键活动
完成整个⼯程的最短时间就是关键路径的⻓度,若关键活动不能按时完成,则整个⼯程的完成时间就会延⻓

事件vk 的最早发⽣时间ve(k)——决定了所有从vk 开始的活动能够开⼯的最早时间
活动ai 的最早开始时间e(i)——指该活动弧的起点所表⽰的事件的最早发⽣时间

事件vk 的最迟发⽣时间vl(k)——它是指在不推迟整个⼯程完成的前提下,该事件最迟必须发⽣的时间。
活动ai 的最迟开始时间l(i)——它是指该活动弧的终点所表示事件的最迟发⽣时间与该活动所需时间之差。

活动ai 的时间余量d(i)=l(i)-e(i)(活动的最晚减去最早),表⽰在不增加完成整个⼯程所需总时间的情况下,活动ai 可以拖延的时间
若⼀个活动的时间余量为零,则说明该活动必须要如期完成,d(i)=0即l(i) = e(i)的活动ai 是关键活动由关键活动组成的路径就是关键路径

求所有事件的最早发⽣时间
按拓扑排序序列,依次求各个顶点的 ve(k):
ve(源点) = 0
ve(k) = Max{ve(j) + Weight(vj , vk )}, vj 为vk 的任意前驱
如果一个结点有多个入度,则求其最大值(前提条件全部完成了,可以进行该事件)
Eg:
在这里插入图片描述

求所有事件的最迟发⽣时间
按逆拓扑排序序列,依次求各个顶点的 vl(k):
vl(汇点) = ve(汇点)
vl(k) = Min{vl(j) - Weight(vk , vj )} , vj 为vk 的任意后继
Eg:
在这里插入图片描述

求所有活动的最早发⽣时间 e( )
若边<vk , vj >表示活动ai ,则有e(i) = ve(k)
(顶点表示事件,边表示活动)
在这里插入图片描述

求所有活动的最迟发⽣时间 l( )
若边<vk , vj >表⽰活动ai ,则有l(i) = vl(j) - Weight(vk , vj )

在这里插入图片描述

求所有活动的时间余量 d( )
d(i) = l(i) - e(i)
在这里插入图片描述

d(k)=0的活动就是关键活动, 由关键活动可得关键路径
若关键活动耗时增加,则整个⼯程的⼯期将增⻓
缩短关键活动的时间,可以缩短整个⼯程的⼯期
当缩短到⼀定程度时,关键活动可能会变成⾮关键活动
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小二康

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

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

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

打赏作者

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

抵扣说明:

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

余额充值