关键路径 java
原理
关键路径是指设计中从输入到输出经过的延时最长的逻辑路径。优化关键路径是一种提高设计工作速度的有效方法。一般地,从输入到输出的延时取决于信号所经过的延时最大路径,而与其他延时小的路径无关。
理解
关键路径就是从起始点到终点需要花费时间最多的路径
关键路径定义
这里写的是一些关于关键路径的定义
ve: 事件最早开始时间(点的最早开始时间)
vl: 事件最迟开始时间(点的最后开始时间)
ee: 活动最早开始时间(边的最早开始时间)
el: 活动最迟开始时间(边的最迟开始时间)
关键事件 : ve == vl
关键活动 : el == ee
ve: 事件最早开始时间是由拓扑排序得到
其实最核心的是 如果一个节点有入度 那么该点的最早开始时间 由入度 的源点的的最早开始时间 + 边长度 其实是一个迭代 (如果有多个,那么取出最大时间)(最开始的是0)
vl: 事件最迟开始时间是指拓扑排序的逆序得到
其实最核心的是 如果一个节点有出度 那么该点的最迟开始时间 是由出度的边的目标节点的最迟开始时间 - 边的权值 (如果有多个,那么取出最小的时间) (最开始的默认值:终点的最早开始时间)
ee: 活动最早开始时间
活动的最早开始时间,是由点的出度的 事件的最早开始事件决定的。
el: 活动最迟开始时间
活动的最迟开始时间,是由边的终点的最迟时间开始 - 边的权值
代码
package com.company;
import java.util.*;
class AoeNode{
String name;
ArcAoeNode firstArc;
public AoeNode(String name) {
this.name = name;
}
}
class ArcAoeNode{
int nextNode;
int weight;
String name;
ArcAoeNode nextArc;
public ArcAoeNode(int nextNode, int weight,String name) {
this.nextNode = nextNode;
this.weight = weight;
this.name = name;
}
}
public class CriticalPath {
List<AoeNode> aoeNodes;
List<ArcAoeNode> arcAoeNodes;
/** ve 事件最早发生时间 */
int[] ve;
/** vl 事件最晚发生时间 */
int[] vl;
/** ee 活动最早发生时间 */
int[] ee;
/** el 活动最晚发生时间 */
int[] el;
/** 遍历的stack */
Stack<Integer> viewStack = new Stack<>();
public CriticalPath(List<AoeNode> aoeNodes) {
this.aoeNodes = aoeNodes;
ve = new int[aoeNodes.size()];
vl = new int[aoeNodes.size()];
getAllArc();
ee = new int[arcAoeNodes.size()];
el = new int[arcAoeNodes.size()];
}
public void getAllArc(){
arcAoeNodes = new ArrayList<>();
for(AoeNode aoeNode: aoeNodes){
for(ArcAoeNode arcAoeNode=aoeNode.firstArc;arcAoeNode!=null;arcAoeNode=arcAoeNode.nextArc){
arcAoeNodes.add(arcAoeNode);
}
}
}
public int getin(int nodeIndex){
int countIn=0;
for(AoeNode aoe: aoeNodes){
ArcAoeNode arcAoeNode = aoe.firstArc;
while (arcAoeNode!=null){
if(arcAoeNode.nextNode == nodeIndex ){
countIn+=1;
}
arcAoeNode = arcAoeNode.nextArc;
}
}
return countIn;
}
// topologic
public boolean topologic(){
Queue<Integer> queue = new LinkedList<>();
int[] book = new int[aoeNodes.size()];
// init
for(int i = 0; i< aoeNodes.size(); i++){
book[i] = getin(i);
if(book[i]==0){
queue.offer(i);
}
}
int visitLen = 0;
while (!queue.isEmpty()){
int poll = queue.poll();
viewStack.push(poll);
visitLen++;
ArcAoeNode arcAoeNode = aoeNodes.get(poll).firstArc;
while (arcAoeNode!=null){
int node = arcAoeNode.nextNode;
ve[node] = Math.max(ve[node],ve[poll]+ arcAoeNode.weight );
book[node]--;
if(book[node]==0){
queue.offer(node);
}
arcAoeNode = arcAoeNode.nextArc;
}
}
return visitLen== aoeNodes.size();
}
public void criticalPath(){
if(!topologic()){
System.out.println("是个环装图,没有关键路径");
return;
}
// vl
// vl init
for(int i=0;i<ve.length;i++){
vl[i] = ve[ve.length-1];
}
while (!viewStack.isEmpty()){
int popValue = viewStack.pop();
ArcAoeNode arcAoeNode = aoeNodes.get(popValue).firstArc;
while (arcAoeNode!=null){
int nextNode = arcAoeNode.nextNode;
vl[popValue] = Math.min(vl[popValue],vl[nextNode]-arcAoeNode.weight);
arcAoeNode = arcAoeNode.nextArc;
}
}
// el ee
int arcCount = 0;
for(int i=0;i<aoeNodes.size();i++){
ArcAoeNode arcAoeNode = aoeNodes.get(i).firstArc;
while (arcAoeNode!=null){
int nextNode = arcAoeNode.nextNode;
ee[arcCount]=ve[i];
el[arcCount]=vl[nextNode]-arcAoeNode.weight;
arcCount++;
arcAoeNode = arcAoeNode.nextArc;
}
}
// 关键事件
System.out.println("关键事件");
for(int i=0;i<aoeNodes.size();i++){
if(vl[i]==ve[i]){
System.out.println(aoeNodes.get(i).name);
}
}
// 关键活动
System.out.println("关键活动");
for(int i=0;i<ee.length;i++){
if(ee[i]==el[i]){
System.out.println(arcAoeNodes.get(i).name);
}
}
}
}
class testCriticalPath{
public static void main(String[] args) {
List<AoeNode> list = new ArrayList<>();
// 加人点
for(int i=0;i<10;i++){
list.add(new AoeNode("V"+i));
}
// 加入边
// v0
AoeNode aoeNode = list.get(0);
aoeNode.firstArc = new ArcAoeNode(1,3,"a0");
aoeNode.firstArc.nextArc = new ArcAoeNode(2,4,"a1");
// v1
aoeNode = list.get(1);
aoeNode.firstArc = new ArcAoeNode(3,5,"a2");
aoeNode.firstArc.nextArc = new ArcAoeNode(4,6,"a3");
// v2
aoeNode = list.get(2);
aoeNode.firstArc = new ArcAoeNode(3,8,"a4");
aoeNode.firstArc.nextArc = new ArcAoeNode(5,7,"a5");
// v3
aoeNode = list.get(3);
aoeNode.firstArc = new ArcAoeNode(4,3,"a6");
// v4
aoeNode = list.get(4);
aoeNode.firstArc = new ArcAoeNode(6,9,"a7");
aoeNode.firstArc.nextArc = new ArcAoeNode(7,4,"a8");
// v5
aoeNode = list.get(5);
aoeNode.firstArc = new ArcAoeNode(7,6,"a9");
// v6
aoeNode = list.get(6);
aoeNode.firstArc = new ArcAoeNode(9,2,"a10");
// v7
aoeNode = list.get(7);
aoeNode.firstArc = new ArcAoeNode(8,5,"a11");
// v8
aoeNode = list.get(8);
aoeNode.firstArc = new ArcAoeNode(9,3,"a12");
// 图的完成
CriticalPath criticalPath = new CriticalPath(list);
criticalPath.criticalPath();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异