本算法为处理无环加权有向图的算法,需要用到最短路径以及拓扑排序,所以,在图中不能存在有向环,否则数据错误,本算法的拓扑排序理论来自于之前的Kosaraju算法,即通过反图的拓扑排序顺序来遍历原图中的所有节点,因为不用判断节点是否被访问,所以不需要布尔数组判断点是否可用。
这里要特别指出书中的一个错误,P427顶端的第一幅图上方的拓扑排序的顺序应为:5,1,3,6,4,0,7,2
本算法由四个类组成,下面是各个类的源代码:
AcyclicSP
package com;
public class AcyclicSP {
private DirectedEdge[] edgeTo;
private double[] distTo;
public AcyclicSP(EdgeWeightedDigraph G) {
edgeTo = new DirectedEdge[G.V()];
distTo = new double[G.V()];
for (int i = 0; i < G.V(); i++)
distTo[i] = Double.POSITIVE_INFINITY;
distTo[5] = 0;
Topological topological = new Topological(G.reverse());
Iterable<Integer> list = topological.order();
for (int v : list) {
relax(G,v);
}
}
public void relax(EdgeWeightedDigraph G, int v) {
for (DirectedEdge e : G.adj(v)) {
int w = e.to();
if (distTo[w] > distTo[v] + e.getWeight()) {
edgeTo[w] = e;
distTo[w] = distTo[v] + e.getWeight();
}
}
}
public static void main(String[] args) {
EdgeWeightedDigraph graph = new EdgeWeightedDigraph(8);
DirectedEdge[] edges = {
new DirectedEdge(5,4,0.35),
new DirectedEdge(4,0,0.38),
new DirectedEdge(4,7,0.37),
new DirectedEdge(5,7,0.28),
new DirectedEdge(5,1,0.32),
new DirectedEdge(0,2,0.26),
new DirectedEdge(3,7,0.39),
new DirectedEdge(1,3,0.29),
new DirectedEdge(7,2,0.34),
new DirectedEdge(6,2,0.40),
new DirectedEdge(3,6,0.52),
new DirectedEdge(6,0,0.58),
new DirectedEdge(6,4,0.93)
};
for (DirectedEdge edge : edges)
graph.addEdge(edge);
AcyclicSP sp = new AcyclicSP(graph);
for (int i = 0; i < graph.V(); i++)
System.out.println(i+" Edge = "+sp.edgeTo[i]+" dist = "+sp.distTo[i]);
}
}
DirectedEdge
package com; public class DirectedEdge { private final int w; private final int v; private final double weight; public DirectedEdge(int v, int w, double weight) { this.v = v; this.w = w; this.weight = weight; } public double getWeight() { return weight; } public int from() { return v; } public int to() { return w; } @Override public String toString() { return "DirectedEdge{" + "w=" + w + ", v=" + v + ", weight=" + weight + '}'; } }
EdgeWeightedDigraph
package com; import java.util.ArrayList; public class EdgeWeightedDigraph { private int V; private int E; private ArrayList<DirectedEdge>[] adj; public EdgeWeightedDigraph(int v) { this.V = v; this.E = 0; adj = new ArrayList[v]; for (int i = 0; i < V; i++) adj[i] = new ArrayList<DirectedEdge>(); } public int V() { return V; } public int E() { return E; } public void addEdge(DirectedEdge e) { int v = e.from(); adj[v].add(e); E++; } public Iterable<DirectedEdge> adj(int v) { return adj[v]; } public Iterable<DirectedEdge> edges() { ArrayList<DirectedEdge> edgesArr = new ArrayList<>(); for (int i = 0; i < V; i++) { for (DirectedEdge e : adj[i]) { edgesArr.add(e); } } return edgesArr; } public EdgeWeightedDigraph reverse() { EdgeWeightedDigraph newGraph = new EdgeWeightedDigraph(8); for (int i = 0; i < V; i++) { for (DirectedEdge e : adj(i)) { DirectedEdge edge = new DirectedEdge(e.to(),e.from(),e.getWeight()); ((ArrayList<DirectedEdge>)newGraph.adj(e.to())).add(edge); } } return newGraph; } }
Topological
package com; import java.util.Stack; public class Topological { private boolean[] visited; private Stack<Integer> reservePost; public Topological(EdgeWeightedDigraph G) { visited = new boolean[G.V()]; reservePost = new Stack<>(); for (int i = 0; i < G.V(); i++) { if (!visited[i]) dfs(G,i); } } public void dfs(EdgeWeightedDigraph G, int v) { visited[v] = true; for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (!visited[w]) dfs(G,w); } reservePost.push(v); } public Iterable<Integer> order() { return reservePost; } }
输出结果: