[数据结构]求关键路径的c++实现(内附最早开始时间和最迟开始时间)

这篇文章通过求aoe最早开始时间以及最迟开始时间来求关键路径
在求之前需要把图放到一个邻接链表之中
关键路径

关键路径是指设计中从输入到输出经过的延时最长的逻辑路径。优化关键路径是一种提高设计工作速度的有效方法。一般地,从输入到输出的延时取决于信号所经过的延时最大路径,而与其他延时小的路径无关。在优化设计过程中关键路径法可以反复使用,直到不可能减少关键路径延时为止。EDA工具中综合器及设计分析器通常都提供关键路径的信息以便设计者改进设计,提高速度。

所以先给出用的顶点结构以及边结构

typedef struct arc {
	int index; // 指向顶点下标
	int info; //边值
	struct arc *nextArc;  //指向下一条边
}arcNode;	//边结构

typedef struct vertex {
	int info;    // 顶点值
	arcNode *firstArc;  //指向第一条边
}vertexNode,*verList;		//顶点结构

typedef struct {
	verList vertices; 	//邻接表 
	int vexNum, arcNum; 	//图的顶点数和边数 
}Graph,*ALGraph;

在求的过程中用到拓扑排序,先给栈定义

typedef struct stack{
	int *base;
	int *top;
	int stackSize;
}stack;

求最早开始时间

下标0太麻烦,所以统一从1开始


/*	G1为邻接链表
*	G2为逆邻接链表,用于求各顶点入度
*	T 用于之后求之后的最迟开始时间,这里没有作用
*/
bool topologicalsort(ALGraph &G1, ALGraph &G2, stack &T)
{
	stack S;
	init_stack(S, G1->vexNum + 1);//初始化栈
	int* inDegree = findinDegree(G2); //对各顶点求入度

	for (int i = 1;i <= G1->vexNum;i++)
	{
		if (inDegree[i] == 0)  //将入度为 0 的顶点入栈
		{
			push(S, i);
		}
	}
	int count = 0; //记录栈中元素的个数
	int i = 1,k = 0;
	while (!isEmpty(S))
	{
		pop(S, i);  //i为当前链表中入度为0的顶点
		push(T, i);
		count++;
		arcNode* p = G1->vertices[i].firstArc;
		for (;p;p = p->nextArc) //遍历一个顶点的所有后继顶点
		{
			k = p -> index;
			if (!(--inDegree[k]))//i顶点的后继顶点入度减一,如果入度为0,则入栈
				push(S, k);
			if (G1->vertices[i].info + p->info > G1->vertices[k].info)
			{
				G1->vertices[k].info = G1->vertices[i].info + p->info;
				G2->vertices[k].info = G1->vertices[k].info;
			}//如果前驱顶点加上边的值比当前顶点值大,则赋值
		}
	}
	if (count < G1->vexNum)
		return false;
	return true;
}

求最迟发生时间

//返回各个顶点最迟发生时间
//path用于存放关键路径
int* latestTime(ALGraph &G1, stack &T,int* &path)
{
	int* lt = new int[G1->vexNum+1];


	int i = 0,j = 1, k = 1,data=1;
	if (!pop(T, i)) //弹出T中最后一个元素,即收束节点
	{
		return NULL;
	}
	lt[i] = G1->vertices[i].info; //收束节点的值等于本身
	for (int n = 0;n <= G1->vexNum;n++)//初始化各个顶点的最迟发生时间
	{
		lt[n] = lt[i];
	}
	while (!isEmpty(T))
	{
		pop(T, k);
		arcNode* p = G1->vertices[k].firstArc;
		if(p) //给第 k 个节点赋值
			path[k] = p->index;
		for (;p;p = p->nextArc) //遍历k节点的所有后继
		{
			j = p -> index; 
			if (lt[k] > G1->vertices[j].info - p->info)
			{
				lt[k] = G1->vertices[j].info - p->info;
				G1->vertices[k].info = G1->vertices[j].info - p->info;
				path[k] = p->index;
			}
		}
	}
	return lt;
}

最后给出测试函数

int main()
{
	ALGraph G1 = new Graph;
	ALGraph G2 = new Graph;
	stack T;
	init_adjList(G1); //初始化邻接表
	init_conAdjList(G1,G2); //初始化逆邻接表
	init_stack(T, G1->vexNum + 1);//初始化栈
	topologicalsort(G1,G2, T);
	int k = *(T.base+1);
	int *a,*c;
	a = traAdjList(G1);
	for (int i = 1;i <= G1->vexNum;i++) 
	{
		cout <<"v"<<i<<"的最早发生时间为"<< a[i]<<'\t';
	}
	cout << endl;
	int* path = new int[G1->vexNum + 1];
	int *b = latestTime(G1,T,path);
	for (int i = 1;i <= G2->vexNum;i++) 
	{
		cout << "v" << i << "的最晚发生时间为" << b[i] << '\t';
	}
	cout << endl;
	cout << "关键路径为:";
	for (int i = 1;k>0;i++)
	{
		cout << k << " -> ";
		k = path[k];
	}
	return 0;
}

测试值
在这里插入图片描述

在这里插入图片描述

有错误欢迎大家指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值