33import java .util .*;
44
55/**
6- * Graph traversals and utilities.
7- *
8- * <p>This class includes a DFS variant that visits a successor only when
9- * <b>all</b> of its predecessors have already been visited. For each step,
10- * it emits an event either for a visit (with an increasing order) or for a skip
11- * explaining that not all parents were visited yet.</p>
12- *
13- * <p>Input is an adjacency list of successors. If a predecessor map is not
14- * provided, it is derived once from the successors map.</p>
6+ * DFS that visits a successor only when all its predecessors are already visited,
7+ * emitting VISIT and SKIP events.
8+ * <p>
9+ * This class includes a DFS variant that visits a successor only when all of its
10+ * predecessors have already been visited
11+ * </p>
12+ * <p>Related reading:
13+ * <ul>
14+ * <li><a href="https://en.wikipedia.org/wiki/Topological_sorting">Topological sorting</a></li>
15+ * <li><a href="https://en.wikipedia.org/wiki/Depth-first_search">Depth-first search</a></li>
16+ * </ul>
17+ * </p>
1518 */
19+
1620public final class GraphTraversal {
1721
1822 private GraphTraversal () {
@@ -23,7 +27,7 @@ private GraphTraversal() {
2327 public static final class TraversalEvent <T > {
2428 private final T node ;
2529 private final Integer order ; // non-null for visit, null for skip
26- private final String note ; // non-null for skip, null for visit
30+ private final String note ; // non-null for skip, null for visit
2731
2832 private TraversalEvent (T node , Integer order , String note ) {
2933 this .node = node ;
@@ -41,13 +45,24 @@ public static <T> TraversalEvent<T> skip(T node, String note) {
4145 return new TraversalEvent <>(Objects .requireNonNull (node ), null , Objects .requireNonNull (note ));
4246 }
4347
44- public boolean isVisit () { return order != null ; }
45- public boolean isSkip () { return order == null ; }
46- public T node () { return node ; }
47- public Integer order () { return order ; }
48- public String note () { return note ; }
48+ public boolean isVisit () {
49+ return order != null ;
50+ }
51+ public boolean isSkip () {
52+ return order == null ;
53+ }
54+ public T node () {
55+ return node ;
56+ }
57+ public Integer order () {
58+ return order ;
59+ }
60+ public String note () {
61+ return note ;
62+ }
4963
50- @ Override public String toString () {
64+ @ Override
65+ public String toString () {
5166 return isVisit () ? "VISIT(" + node + ", order=" + order + ")" : "SKIP(" + node + ", " + note + ")" ;
5267 }
5368 }
@@ -77,8 +92,7 @@ public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(Map<T, List<T>> succ
7792 /**
7893 * Same as {@link #dfsRecursiveOrder(Map, Object)} but with an explicit predecessors map.
7994 */
80- public static <T > List <TraversalEvent <T >> dfsRecursiveOrder (
81- Map <T , List <T >> successors , Map <T , List <T >> predecessors , T start ) {
95+ public static <T > List <TraversalEvent <T >> dfsRecursiveOrder (Map <T , List <T >> successors , Map <T , List <T >> predecessors , T start ) {
8296
8397 if (successors == null || predecessors == null ) {
8498 throw new IllegalArgumentException ("successors and predecessors must not be null" );
@@ -97,13 +111,7 @@ public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(
97111 return Collections .unmodifiableList (events );
98112 }
99113
100- private static <T > void dfs (
101- T u ,
102- Map <T , List <T >> succ ,
103- Map <T , List <T >> pred ,
104- Set <T > visited ,
105- int [] order ,
106- List <TraversalEvent <T >> out ) {
114+ private static <T > void dfs (T u , Map <T , List <T >> succ , Map <T , List <T >> pred , Set <T > visited , int [] order , List <TraversalEvent <T >> out ) {
107115
108116 if (!visited .add (u )) {
109117 return ; // already visited
0 commit comments