本算法为处理无环加权有向图的算法,需要用到最短路径以及拓扑排序,所以,在图中不能存在有向环,否则数据错误,本算法的拓扑排序理论来自于之前的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 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[] 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();
}
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 adj(int v) {
return adj[v];
}
public Iterable edges() {
ArrayList 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)newGraph.adj(e.to())).add(edge);
}
}
return newGraph;
}
}
Topological
package com;
import java.util.Stack;
public class Topological {
private boolean[] visited;
private Stack 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 order() {
return reservePost;
}
}