3
3
import java .util .*;
4
4
5
5
/**
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>
15
18
*/
19
+
16
20
public final class GraphTraversal {
17
21
18
22
private GraphTraversal () {
@@ -23,7 +27,7 @@ private GraphTraversal() {
23
27
public static final class TraversalEvent <T > {
24
28
private final T node ;
25
29
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
27
31
28
32
private TraversalEvent (T node , Integer order , String note ) {
29
33
this .node = node ;
@@ -41,13 +45,24 @@ public static <T> TraversalEvent<T> skip(T node, String note) {
41
45
return new TraversalEvent <>(Objects .requireNonNull (node ), null , Objects .requireNonNull (note ));
42
46
}
43
47
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
+ }
49
63
50
- @ Override public String toString () {
64
+ @ Override
65
+ public String toString () {
51
66
return isVisit () ? "VISIT(" + node + ", order=" + order + ")" : "SKIP(" + node + ", " + note + ")" ;
52
67
}
53
68
}
@@ -77,8 +92,7 @@ public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(Map<T, List<T>> succ
77
92
/**
78
93
* Same as {@link #dfsRecursiveOrder(Map, Object)} but with an explicit predecessors map.
79
94
*/
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 ) {
82
96
83
97
if (successors == null || predecessors == null ) {
84
98
throw new IllegalArgumentException ("successors and predecessors must not be null" );
@@ -97,13 +111,7 @@ public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(
97
111
return Collections .unmodifiableList (events );
98
112
}
99
113
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 ) {
107
115
108
116
if (!visited .add (u )) {
109
117
return ; // already visited
0 commit comments