以下是基于
this page提供的解释的算法实现
有一个包装类可以保存任务,成本和关键路径成本.首先,将关键成本计算为所有依赖关系的最大临界成本加上自己的成本.然后,一旦关键成本可用,它就会使用比较器根据关键成本对任务进行排序,并将依赖关系作为平局(如果没有依赖关系则随机选择).请注意,如果存在循环,则会抛出异常,如果任何成本为负,则会失败.
这是实施:
public class CriticalPath {
public static void main(String[] args) {
//The example dependency graph from
//http://www.ctl.ua.edu/math103/scheduling/scheduling_algorithms.htm
HashSet allTasks = new HashSet();
Task end = new Task("End", 0);
Task F = new Task("F", 2, end);
Task A = new Task("A", 3, end);
Task X = new Task("X", 4, F, A);
Task Q = new Task("Q", 2, A, X);
Task start = new Task("Start", 0, Q);
allTasks.add(end);
allTasks.add(F);
allTasks.add(A);
allTasks.add(X);
allTasks.add(Q);
allTasks.add(start);
System.out.println("Critical Path: "+Arrays.toString(criticalPath(allTasks)));
}
//A wrapper class to hold the tasks during the calculation
public static class Task{
//the actual cost of the task
public int cost;
//the cost of the task along the critical path
public int criticalCost;
//a name for the task for printing
public String name;
//the tasks on which this task is dependant
public HashSet dependencies = new HashSet();
public Task(String name, int cost, Task... dependencies) {
this.name = name;
this.cost = cost;
for(Task t : dependencies){
this.dependencies.add(t);
}
}
@Override
public String toString() {
return name+": "+criticalCost;
}
public boolean isDependent(Task t){
//is t a direct dependency?
if(dependencies.contains(t)){
return true;
}
//is t an indirect dependency
for(Task dep : dependencies){
if(dep.isDependent(t)){
return true;
}
}
return false;
}
}
public static Task[] criticalPath(Set tasks){
//tasks whose critical cost has been calculated
HashSet completed = new HashSet();
//tasks whose ciritcal cost needs to be calculated
HashSet remaining = new HashSet(tasks);
//Backflow algorithm
//while there are tasks whose critical cost isn't calculated.
while(!remaining.isEmpty()){
boolean progress = false;
//find a new task to calculate
for(Iterator it = remaining.iterator();it.hasNext();){
Task task = it.next();
if(completed.containsAll(task.dependencies)){
//all dependencies calculated, critical cost is max dependency
//critical cost, plus our cost
int critical = 0;
for(Task t : task.dependencies){
if(t.criticalCost > critical){
critical = t.criticalCost;
}
}
task.criticalCost = critical+task.cost;
//set task as calculated an remove
completed.add(task);
it.remove();
//note we are making progress
progress = true;
}
}
//If we haven't made any progress then a cycle must exist in
//the graph and we wont be able to calculate the critical path
if(!progress) throw new RuntimeException("Cyclic dependency, algorithm stopped!");
}
//get the tasks
Task[] ret = completed.toArray(new Task[0]);
//create a priority list
Arrays.sort(ret, new Comparator() {
@Override
public int compare(Task o1, Task o2) {
//sort by cost
int i= o2.criticalCost-o1.criticalCost;
if(i != 0)return i;
//using dependency as a tie breaker
//note if a is dependent on b then
//critical cost a must be >= critical cost of b
if(o1.isDependent(o2))return -1;
if(o2.isDependent(o1))return 1;
return 0;
}
});
return ret;
}
}