Last active
October 20, 2016 09:56
-
-
Save vnprc/69a6d45bd8daabd45dbca8dd451584bf to your computer and use it in GitHub Desktop.
An implementation of Kahn's topographical sort algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Queue; | |
import java.util.Set; | |
public class TopologicalSort { | |
public List<Node> topographicalSort(Set<Node> nodes) | |
throws GraphException { | |
//map number of incoming dependencies for each node | |
Map<Node, Integer> inDegrees = new HashMap<>(); | |
for (Node node : nodes) { | |
for (Node child : node.getDependencies()) { | |
//add or increment inDegree | |
inDegrees.compute(child, (key, oldValue) -> oldValue == null ? 1 : oldValue + 1); | |
} | |
//make sure all nodes are added | |
inDegrees.computeIfAbsent(node, value -> 0); | |
} | |
//add all nodes with no incoming dependencies | |
Queue<Node> queue = new LinkedList<>(); | |
for (Node node : nodes) { | |
if (inDegrees.get(node) == 0) { | |
queue.add(node); | |
} | |
} | |
//iteratively subtract dependencies to leaf nodes, add new leaf nodes | |
LinkedList<Node> results = new LinkedList<>(); | |
while (!queue.isEmpty()) { | |
Node node = queue.remove(); | |
results.addFirst(node); | |
for (Node child : node.getDependencies()) { | |
inDegrees.compute(child, (key, value) -> value - 1); | |
if (inDegrees.get(child) == 0) { | |
queue.add(child); | |
} | |
} | |
} | |
//final check for cycles | |
if (results.size() != nodes.size()) { | |
throw new GraphException("Cyclical graph detected"); | |
} | |
return results; | |
} | |
public class GraphException extends Exception { | |
public GraphException(String message) { | |
super(message); | |
} | |
} | |
public static class Node { | |
private String name; | |
private Set<Node> dependencies = new HashSet<>(); | |
public Node(String name) { | |
this.name = name; | |
} | |
public String getName() { | |
return name; | |
} | |
public void addDependency(Node node) { | |
dependencies.add(node); | |
} | |
public Set<Node> getDependencies() { | |
return dependencies; | |
} | |
@Override | |
public String toString() { | |
return name; | |
} | |
} | |
public static void main(String[] args) throws GraphException { | |
Node a = new Node("A"); | |
Node b = new Node("B"); | |
Node c = new Node("C"); | |
Node d = new Node("D"); | |
Node e = new Node("E"); | |
Node f = new Node("F"); | |
Node g = new Node("G"); | |
Node h = new Node("H"); | |
b.addDependency(a); | |
d.addDependency(c); | |
d.addDependency(b); | |
e.addDependency(d); | |
f.addDependency(d); | |
f.addDependency(c); | |
g.addDependency(f); | |
g.addDependency(b); | |
h.addDependency(e); | |
Set<Node> nodes = new HashSet<>(Arrays.asList(a, b, c, d, e, f, g, h)); | |
System.out.println(new TopologicalSort().topographicalSort(nodes)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment