1.AOE图:
2.AOE图邻接链表存储结构:
3.代码实现
3.1.实体及参数初始化
//邻接表的链表节点
@Data
public class LinkedNode {
//邻接链表顶点编号
private int nodeNum;
//头节点到当前链表节点的 弧上的权值
private int weight;
//当前链表节点指向的下一个链表节点
private LinkedNode nextLinkedNode;
}
//邻接表中头节点
@Data
public class HeadNode {
//节点编号
private int nodeNum;
//指向的下一个链表节点
private LinkedNode nextLinkedNode;
}
//AOE网络 图
@Data
public class AoeGraph {
//顶点数量
private int verticesNum ;
//边数量
private int edgeNum;
//图的邻接表的 头结点集合
private HeadNode[] headNode;
}
将AOE图及其邻接链表的关系转化成实体:
//AOE图的邻接链表的初始化
static LinkedNode v0_2 = new LinkedNode(2,30,null);
static LinkedNode v0_1 = new LinkedNode(1,10,v0_2);
static HeadNode v0 = new HeadNode(0,v0_1);
static LinkedNode v1_5 = new LinkedNode(5,50,null);
static LinkedNode v1_3 = new LinkedNode(3,30,v1_5);
static HeadNode v1 = new HeadNode(1,v1_3);
static LinkedNode v2_5 = new LinkedNode(5,20,null);
static LinkedNode v2_4 = new LinkedNode(4,30,v2_5);
static HeadNode v2 = new HeadNode(2,v2_4);
static HeadNode v3= new HeadNode(3,null);
static LinkedNode v4_3 = new LinkedNode(3,10,null);
static HeadNode v4 = new HeadNode(4,v4_3);
static LinkedNode v5_3 = new LinkedNode(3,20,null);
static HeadNode v5 = new HeadNode(5,v5_3);
//邻接链表的头节点集合
static HeadNode[] headNodeArr = new HeadNode[]{v0,v1,v2,v3,v4,v5};
//AOE图
static AoeGraph aoeGraph = new AoeGraph(6,8,headNodeArr);
3.2.代码实现
public static void main(String[] args) {
int length = criticalPathCalc(aoeGraph);
System.out.println("length : "+length);
}
public static int criticalPathCalc(AoeGraph aoeGraph){
int verticesNum = aoeGraph.getVerticesNum();//图的 顶点数量
HeadNode[] headNodeArr = aoeGraph.getHeadNode(); //图的邻接表的 头结点集合
int [] inDegree = new int[verticesNum]; //记录每个顶点的 实时入度 (初始化后,默认每位都是0)
int [] weightSum = new int[verticesNum];//记录从开始顶点到 当前顶点的 实时最大权值 (初始化后,默认每位都是0)
ConcurrentLinkedQueue<HeadNode> inDegreeZero = new ConcurrentLinkedQueue<>();//记录入度为0 的顶点
int nodeNum =0 ; //节点的编号
//计算每个节点的入度
for (int i = 0; i < headNodeArr.length; i++) {
HeadNode headNode = headNodeArr[i];//当前操作的邻接邻接链表头节点
LinkedNode linkedNode = headNode.getNextLinkedNode();//当前头节点的指向的 邻接节点;
while (null!=linkedNode){
inDegree[linkedNode.getNodeNum()]++;//指向的 邻接节点的 入度加1
linkedNode = linkedNode.getNextLinkedNode();//指针指向 头节点的下一个邻接节点
}
}
//将入度为0 的节点 放入队列
for (int i = 0; i < inDegree.length; i++) {
if(0==inDegree[i]){
inDegreeZero.add(headNodeArr[i]);//将入度为0 的节点放入队列
}
}
//只要队列不为空,就不断弹出入度为0的节点。相当于在图中擦去入度为0的节点及其相关边
while (!inDegreeZero.isEmpty()){
HeadNode headNode = inDegreeZero.poll();//弹出 入度为0的 节点 作为 =》头节点(相当于擦去入度为0的节点)
System.out.println(headNode.getNodeNum());//输出拓扑序列
LinkedNode nextLinkedNode = headNode.getNextLinkedNode();//头节点指向的 =》 链表节点
while (null!=nextLinkedNode){
nodeNum = nextLinkedNode.getNodeNum();//当前头节点指向的 链表节点的 编号
inDegree[nodeNum]--;//链表节点入度减1 (相当于擦去入度为0的节点到其指向的链表节点之前的弧)
if(0==inDegree[nodeNum]){
inDegreeZero.add(headNodeArr[nodeNum]);//如果当前链表节点入度=0,放入队列(准备循环把入度为0的它也擦掉)
}
//开始节点到当前链表节点的累加权值 < 当前头节点到当前链表节点的弧线权值 + 开始节点到当前头节点的累加权值
if(weightSum[nodeNum] < nextLinkedNode.getWeight()+ weightSum[headNode.getNodeNum()]){
//开始节点到当前链表节点的最大权值 = 上诉比较的最大值
weightSum[nodeNum] = nextLinkedNode.getWeight() + weightSum[headNode.getNodeNum()];
}
nextLinkedNode = nextLinkedNode.getNextLinkedNode();//获取头节点的下一个链表节点
}
}
return weightSum[nodeNum];//
}
3.3.输出
0
1
2
4
5
3
length : 80