Skip to content

Commit b113746

Browse files
Removed changed in PartitionProblem.java, Renamed class name to be straightforward about the implementation.Added full names instead of shortcuts, and included record.
1 parent 0a990c6 commit b113746

File tree

3 files changed

+58
-65
lines changed

3 files changed

+58
-65
lines changed

src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/**
22
* @author Md Asif Joardar
33
*
44
* Description: The partition problem is a classic problem in computer science

src/main/java/com/thealgorithms/graph/GraphTraversal.java renamed to src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,53 +24,46 @@
2424
* </p>
2525
*/
2626

27-
public final class GraphTraversal {
27+
public final class PredecessorConstrainedDfs {
2828

29-
private GraphTraversal() {
29+
private PredecessorConstrainedDfs() {
3030
// utility class
3131
}
3232

3333
/** An event emitted by the traversal: either a VISIT with an order, or a SKIP with a note. */
34-
public static final class TraversalEvent<T> {
35-
private final T node;
36-
private final Integer order; // non-null for visit, null for skip
37-
private final String note; // non-null for skip, null for visit
38-
39-
private TraversalEvent(T node, Integer order, String note) {
40-
this.node = node;
41-
this.order = order;
42-
this.note = note;
34+
public record TraversalEvent<T>(
35+
T node,
36+
Integer order, // non-null for visit, null for skip
37+
String note // non-null for skip, null for visit
38+
) {
39+
public TraversalEvent {
40+
Objects.requireNonNull(node);
41+
// order and note can be null based on event type
4342
}
4443

4544
/** A visit event with an increasing order (0,1,2,...) */
4645
public static <T> TraversalEvent<T> visit(T node, int order) {
47-
return new TraversalEvent<>(Objects.requireNonNull(node), order, null);
46+
return new TraversalEvent<>(node, order, null);
4847
}
4948

5049
/** A skip event with an explanatory note (e.g., not all parents visited yet). */
5150
public static <T> TraversalEvent<T> skip(T node, String note) {
52-
return new TraversalEvent<>(Objects.requireNonNull(node), null, Objects.requireNonNull(note));
51+
return new TraversalEvent<>(node, null, Objects.requireNonNull(note));
5352
}
5453

5554
public boolean isVisit() {
5655
return order != null;
5756
}
57+
5858
public boolean isSkip() {
5959
return order == null;
6060
}
61-
public T node() {
62-
return node;
63-
}
64-
public Integer order() {
65-
return order;
66-
}
67-
public String note() {
68-
return note;
69-
}
7061

7162
@Override
7263
public String toString() {
73-
return isVisit() ? "VISIT(" + node + ", order=" + order + ")" : "SKIP(" + node + ", " + note + ")";
64+
return isVisit()
65+
? "VISIT(" + node + ", order=" + order + ")"
66+
: "SKIP(" + node + ", " + note + ")";
7467
}
7568
}
7669

@@ -118,56 +111,56 @@ public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(Map<T, List<T>> succ
118111
return Collections.unmodifiableList(events);
119112
}
120113

121-
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) {
114+
private static <T> void dfs(T currentNode, Map<T, List<T>> successors, Map<T, List<T>> predecessors, Set<T> visited, int[] order, List<TraversalEvent<T>> result) {
122115

123-
if (!visited.add(u)) {
116+
if (!visited.add(currentNode)) {
124117
return; // already visited
125118
}
126-
out.add(TraversalEvent.visit(u, order[0]++)); // record visit and increment
119+
result.add(TraversalEvent.visit(currentNode, order[0]++)); // record visit and increment
127120

128-
for (T v : succ.getOrDefault(u, List.of())) {
129-
if (visited.contains(v)) {
121+
for (T childNode : successors.getOrDefault(currentNode, List.of())) {
122+
if (visited.contains(childNode)) {
130123
continue;
131124
}
132-
if (allParentsVisited(v, visited, pred)) {
133-
dfs(v, succ, pred, visited, order, out);
125+
if (allParentsVisited(childNode, visited, predecessors)) {
126+
dfs(childNode, successors, predecessors, visited, order, result);
134127
} else {
135-
out.add(TraversalEvent.skip(v, "⛔ Skipping " + v + ": not all parents are visited yet."));
128+
result.add(TraversalEvent.skip(childNode, "⛔ Skipping " + childNode + ": not all parents are visited yet."));
136129
// do not mark visited; it may be visited later from another parent
137130
}
138131
}
139132
}
140133

141-
private static <T> boolean allParentsVisited(T node, Set<T> visited, Map<T, List<T>> pred) {
142-
for (T p : pred.getOrDefault(node, List.of())) {
143-
if (!visited.contains(p)) {
134+
private static <T> boolean allParentsVisited(T node, Set<T> visited, Map<T, List<T>> predecessors) {
135+
for (T parent : predecessors.getOrDefault(node, List.of())) {
136+
if (!visited.contains(parent)) {
144137
return false;
145138
}
146139
}
147140
return true;
148141
}
149142

150-
private static <T> boolean appearsAnywhere(Map<T, List<T>> succ, T node) {
151-
if (succ.containsKey(node)) {
143+
private static <T> boolean appearsAnywhere(Map<T, List<T>> successors, T node) {
144+
if (successors.containsKey(node)) {
152145
return true;
153146
}
154-
for (List<T> nbrs : succ.values()) {
155-
if (nbrs != null && nbrs.contains(node)) {
147+
for (List<T> neighbours : successors.values()) {
148+
if (neighbours != null && neighbours.contains(node)) {
156149
return true;
157150
}
158151
}
159152
return false;
160153
}
161154

162-
private static <T> Map<T, List<T>> derivePredecessors(Map<T, List<T>> succ) {
163-
Map<T, List<T>> pred = new HashMap<>();
155+
private static <T> Map<T, List<T>> derivePredecessors(Map<T, List<T>> successors) {
156+
Map<T, List<T>> predecessors = new HashMap<>();
164157
// ensure keys exist for all nodes appearing anywhere
165-
for (Map.Entry<T, List<T>> e : succ.entrySet()) {
166-
pred.computeIfAbsent(e.getKey(), k -> new ArrayList<>());
167-
for (T v : e.getValue()) {
168-
pred.computeIfAbsent(v, k -> new ArrayList<>()).add(e.getKey());
158+
for (Map.Entry<T, List<T>> entry : successors.entrySet()) {
159+
predecessors.computeIfAbsent(entry.getKey(), key -> new ArrayList<>());
160+
for (T childNode : entry.getValue()) {
161+
predecessors.computeIfAbsent(childNode, key -> new ArrayList<>()).add(entry.getKey());
169162
}
170163
}
171-
return pred;
164+
return predecessors;
172165
}
173166
}

src/test/java/com/thealgorithms/graph/GraphTraversalTest.java renamed to src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.junit.jupiter.api.Assertions.assertThrows;
55

6-
import com.thealgorithms.graph.GraphTraversal.TraversalEvent;
6+
import com.thealgorithms.graph.PredecessorConstrainedDfs.TraversalEvent;
77
import java.util.HashMap;
88
import java.util.LinkedHashMap;
99
import java.util.List;
1010
import java.util.Map;
1111
import org.junit.jupiter.api.Test;
1212

13-
class GraphTraversalTest {
13+
class PredecessorConstrainedDfsTest {
1414

1515
// A -> B, A -> C, B -> D, C -> D (classic diamond)
1616
private static Map<String, List<String>> diamond() {
@@ -24,7 +24,7 @@ private static Map<String, List<String>> diamond() {
2424

2525
@Test
2626
void dfsRecursiveOrderEmitsSkipUntilAllParentsVisited() {
27-
List<TraversalEvent<String>> events = GraphTraversal.dfsRecursiveOrder(diamond(), "A");
27+
List<TraversalEvent<String>> events = PredecessorConstrainedDfs.dfsRecursiveOrder(diamond(), "A");
2828

2929
// Expect visits in order and a skip for first time we meet D (via B) before C is visited.
3030
var visits = events.stream().filter(TraversalEvent::isVisit).toList();
@@ -49,39 +49,39 @@ void dfsRecursiveOrderEmitsSkipUntilAllParentsVisited() {
4949

5050
@Test
5151
void returnsEmptyWhenStartNotInGraph() {
52-
Map<Integer, List<Integer>> g = Map.of(1, List.of(2), 2, List.of(1));
53-
assertThat(GraphTraversal.dfsRecursiveOrder(g, 99)).isEmpty();
52+
Map<Integer, List<Integer>> graph = Map.of(1, List.of(2), 2, List.of(1));
53+
assertThat(PredecessorConstrainedDfs.dfsRecursiveOrder(graph, 99)).isEmpty();
5454
}
5555

5656
@Test
5757
void nullSuccessorsThrows() {
58-
assertThrows(IllegalArgumentException.class, () -> GraphTraversal.dfsRecursiveOrder(null, "A"));
58+
assertThrows(IllegalArgumentException.class, () -> PredecessorConstrainedDfs.dfsRecursiveOrder(null, "A"));
5959
}
6060

6161
@Test
6262
void worksWithExplicitPredecessors() {
63-
Map<Integer, List<Integer>> succ = new HashMap<>();
64-
succ.put(10, List.of(20));
65-
succ.put(20, List.of(30));
66-
succ.put(30, List.of());
63+
Map<Integer, List<Integer>> successors = new HashMap<>();
64+
successors.put(10, List.of(20));
65+
successors.put(20, List.of(30));
66+
successors.put(30, List.of());
6767

68-
Map<Integer, List<Integer>> pred = new HashMap<>();
69-
pred.put(10, List.of());
70-
pred.put(20, List.of(10));
71-
pred.put(30, List.of(20));
68+
Map<Integer, List<Integer>> predecessors = new HashMap<>();
69+
predecessors.put(10, List.of());
70+
predecessors.put(20, List.of(10));
71+
predecessors.put(30, List.of(20));
7272

73-
var events = GraphTraversal.dfsRecursiveOrder(succ, pred, 10);
73+
var events = PredecessorConstrainedDfs.dfsRecursiveOrder(successors, predecessors, 10);
7474
var visitNodes = events.stream().filter(TraversalEvent::isVisit).map(TraversalEvent::node).toList();
7575
assertThat(visitNodes).containsExactly(10, 20, 30);
7676
}
7777

7878
@Test
7979
void cycleProducesSkipsButNoInfiniteRecursion() {
80-
Map<String, List<String>> succ = new LinkedHashMap<>();
81-
succ.put("X", List.of("Y"));
82-
succ.put("Y", List.of("X")); // 2-cycle
80+
Map<String, List<String>> successors = new LinkedHashMap<>();
81+
successors.put("X", List.of("Y"));
82+
successors.put("Y", List.of("X")); // 2-cycle
8383

84-
var events = GraphTraversal.dfsRecursiveOrder(succ, "X");
84+
var events = PredecessorConstrainedDfs.dfsRecursiveOrder(successors, "X");
8585
// Only X is visited; encountering Y from X causes skip because Y's parent X is visited,
8686
// but when recursing to Y we'd hit back to X (already visited) and stop; no infinite loop.
8787
assertThat(events.stream().anyMatch(TraversalEvent::isVisit)).isTrue();

0 commit comments

Comments
 (0)