Just to augment the great solution by @templatetypedef a bit, I added some unit tests to give some added confidence for myself and others to use. Hope this helps...
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Test;
public class TestTopologicalSort {
@Test (expected=java.lang.NullPointerException.class)
public void testNullGraph() {
final List orderedLayers = TopologicalSort.sort(null);
}
@Test
public void testEmptyGraph() {
final DirectedGraph dag = new DirectedGraph();
final List orderedLayers = TopologicalSort.sort(dag);
assertEquals(0, orderedLayers.size());
}
@Test
public void testSingleVertex() {
final DirectedGraph dag = new DirectedGraph();
dag.addNode("a");
final List orderedLayers = TopologicalSort.sort(dag);
assertEquals(1, orderedLayers.size());
assertTrue(orderedLayers.contains("a"));
}
@Test
public void testMultipleVertices() {
final DirectedGraph dag = new DirectedGraph();
dag.addNode("a");
dag.addNode("b");
final List orderedLayers = TopologicalSort.sort(dag);
assertEquals(2, orderedLayers.size());
assertTrue(orderedLayers.contains("a"));
assertTrue(orderedLayers.contains("b"));
}
@Test (expected=java.util.NoSuchElementException.class)
public void testBogusEdge() {
final DirectedGraph dag = new DirectedGraph();
dag.addNode("a");
dag.addEdge("a", "b");
}
@Test
public void testSimpleDag() {
final DirectedGraph dag = new DirectedGraph();
dag.addNode("b");
dag.addNode("a");
dag.addEdge("a", "b");
final List orderedLayers = TopologicalSort.sort(dag);
assertEquals(2, orderedLayers.size());
assertTrue(orderedLayers.get(0).equals("a"));
assertTrue(orderedLayers.get(1).equals("b"));
}
@Test
public void testComplexGraph() {
// node b has two incoming edges
final DirectedGraph dag = new DirectedGraph();
dag.addNode("a");
dag.addNode("b");
dag.addNode("c");
dag.addNode("d");
dag.addNode("e");
dag.addNode("f");
dag.addNode("g");
dag.addNode("h");
dag.addEdge("a", "b");
dag.addEdge("a", "c");
dag.addEdge("c", "d");
dag.addEdge("d", "b");
dag.addEdge("c", "e");
dag.addEdge("f", "g");
final List orderedLayers = TopologicalSort.sort(dag);
assertEquals(8, orderedLayers.size());
assertTrue(orderedLayers.indexOf("a") < orderedLayers.indexOf("b"));
assertTrue(orderedLayers.indexOf("a") < orderedLayers.indexOf("c"));
assertTrue(orderedLayers.indexOf("c") < orderedLayers.indexOf("d"));
assertTrue(orderedLayers.indexOf("c") < orderedLayers.indexOf("e"));
assertTrue(orderedLayers.indexOf("d") < orderedLayers.indexOf("b"));
assertTrue(orderedLayers.indexOf("f") < orderedLayers.indexOf("g"));
}
@Test (expected=java.lang.IllegalArgumentException.class)
public void testCycle() {
// cycle between a, c, and d
final DirectedGraph dag = new DirectedGraph();
dag.addNode("a");
dag.addNode("b");
dag.addNode("c");
dag.addNode("d");
dag.addNode("e");
dag.addNode("f");
dag.addNode("g");
dag.addNode("h");
dag.addEdge("a", "b");
dag.addEdge("a", "c");
dag.addEdge("c", "d");
dag.addEdge("d", "a");
dag.addEdge("c", "e");
dag.addEdge("f", "g");
final List orderedLayers = TopologicalSort.sort(dag);
}
}