Skip to content

Commit 497ca85

Browse files
williamfisetclaude
andauthored
Refactor ConnectedComponentsDfsSolver: rename, clean up, add docs (williamfiset#1300)
- Rename to ConnectedComponentsDfs for brevity - Eliminate visited array by using componentIds with -1 sentinel - Make component IDs 0-indexed for consistency with UnionFind variant - Add Javadoc with complexity, graph diagram, componentId() method - Make solve() private, graph field final - Update BUILD and README Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e6cac02 commit 497ca85

File tree

4 files changed

+140
-117
lines changed

4 files changed

+140
-117
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ $ java -cp classes com.williamfiset.algorithms.search.BinarySearch
208208
- [Bridges/cut edges (adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/BridgesAdjacencyList.java) **- O(V+E)**
209209
- [Boruvkas (adjacency list, min spanning tree algorithm)](src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java) **- O(Elog(V))**
210210
- [Find connected components (adjacency list, union find)](src/main/java/com/williamfiset/algorithms/graphtheory/ConnectedComponentsUnionFind.java) **- O(V+E)**
211-
- [Find connected components (adjacency list, DFS)](src/main/java/com/williamfiset/algorithms/graphtheory/ConnectedComponentsDfsSolverAdjacencyList.java) **- O(V+E)**
211+
- [Find connected components (adjacency list, DFS)](src/main/java/com/williamfiset/algorithms/graphtheory/ConnectedComponentsDfs.java) **- O(V+E)**
212212
- [Depth first search (adjacency list, iterative)](src/main/java/com/williamfiset/algorithms/graphtheory/DepthFirstSearchAdjacencyListIterative.java) **- O(V+E)**
213213
- [Depth first search (adjacency list, iterative, fast stack)](src/main/java/com/williamfiset/algorithms/graphtheory/DepthFirstSearchAdjacencyListIterativeFastStack.java) **- O(V+E)**
214214
- [:movie_camera:](https://www.youtube.com/watch?v=7fujbpJ0LB4) [Depth first search (adjacency list, recursive)](src/main/java/com/williamfiset/algorithms/graphtheory/DepthFirstSearchAdjacencyListRecursive.java) **- O(V+E)**

src/main/java/com/williamfiset/algorithms/graphtheory/BUILD

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ java_binary(
8383
runtime_deps = [":graphtheory"],
8484
)
8585

86-
# bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:ConnectedComponentsDfsSolverAdjacencyList
86+
# bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:ConnectedComponentsDfs
8787
java_binary(
88-
name = "ConnectedComponentsDfsSolverAdjacencyList",
89-
main_class = "com.williamfiset.algorithms.graphtheory.ConnectedComponentsDfsSolverAdjacencyList",
88+
name = "ConnectedComponentsDfs",
89+
main_class = "com.williamfiset.algorithms.graphtheory.ConnectedComponentsDfs",
9090
runtime_deps = [":graphtheory"],
9191
)
9292

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* Connected Components — Adjacency List (DFS)
3+
*
4+
* <p>Finds all connected components of an undirected graph using depth-first
5+
* search. Each unvisited node starts a new DFS that labels every reachable node
6+
* with the same component id.
7+
*
8+
* <p>For directed graphs, use Tarjan's or Kosaraju's algorithm to find
9+
* <em>strongly</em> connected components instead.
10+
*
11+
* <p>Time: O(V + E)
12+
* <p>Space: O(V)
13+
*
14+
* @author William Fiset, william.alexandre.fiset@gmail.com
15+
*/
16+
package com.williamfiset.algorithms.graphtheory;
17+
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.List;
21+
22+
public class ConnectedComponentsDfs {
23+
24+
private final int n;
25+
private final List<List<Integer>> graph;
26+
private boolean solved;
27+
private int componentCount;
28+
private int[] componentIds;
29+
30+
public ConnectedComponentsDfs(List<List<Integer>> graph) {
31+
if (graph == null) {
32+
throw new IllegalArgumentException();
33+
}
34+
this.n = graph.size();
35+
this.graph = graph;
36+
}
37+
38+
/**
39+
* Returns the number of connected components.
40+
*/
41+
public int countComponents() {
42+
solve();
43+
return componentCount;
44+
}
45+
46+
/**
47+
* Returns the component id of the given node. Component ids are 0-indexed.
48+
*/
49+
public int componentId(int node) {
50+
solve();
51+
return componentIds[node];
52+
}
53+
54+
/**
55+
* Returns the component id array where {@code componentIds[i]} is the
56+
* component id of node i. Component ids are 0-indexed.
57+
*/
58+
public int[] getComponentIds() {
59+
solve();
60+
return componentIds;
61+
}
62+
63+
private void solve() {
64+
if (solved) {
65+
return;
66+
}
67+
68+
componentIds = new int[n];
69+
Arrays.fill(componentIds, -1);
70+
71+
for (int i = 0; i < n; i++) {
72+
if (componentIds[i] == -1) {
73+
dfs(i, componentCount++);
74+
}
75+
}
76+
77+
solved = true;
78+
}
79+
80+
private void dfs(int at, int id) {
81+
componentIds[at] = id;
82+
for (int to : graph.get(at)) {
83+
if (componentIds[to] == -1) {
84+
dfs(to, id);
85+
}
86+
}
87+
}
88+
89+
// ==================== Main ====================
90+
91+
//
92+
// 0 --- 1 3 --- 6
93+
// | / | | |
94+
// | / | | |
95+
// 7 2 - 5 4 9 10
96+
//
97+
// 8
98+
//
99+
// Components: {0,1,2,5,7}, {3,4,6,9}, {8}, {10}
100+
// Count: 4
101+
//
102+
public static void main(String[] args) {
103+
int n = 11;
104+
List<List<Integer>> graph = createGraph(n);
105+
106+
addUndirectedEdge(graph, 0, 1);
107+
addUndirectedEdge(graph, 1, 7);
108+
addUndirectedEdge(graph, 7, 0);
109+
addUndirectedEdge(graph, 1, 2);
110+
addUndirectedEdge(graph, 2, 5);
111+
addUndirectedEdge(graph, 3, 4);
112+
addUndirectedEdge(graph, 3, 6);
113+
addUndirectedEdge(graph, 6, 9);
114+
115+
ConnectedComponentsDfs solver = new ConnectedComponentsDfs(graph);
116+
117+
System.out.printf("Number of components: %d%n", solver.countComponents());
118+
119+
for (int i = 0; i < n; i++) {
120+
System.out.printf("Node %d -> component %d%n", i, solver.componentId(i));
121+
}
122+
}
123+
124+
private static List<List<Integer>> createGraph(int n) {
125+
List<List<Integer>> graph = new ArrayList<>(n);
126+
for (int i = 0; i < n; i++) {
127+
graph.add(new ArrayList<>());
128+
}
129+
return graph;
130+
}
131+
132+
private static void addUndirectedEdge(List<List<Integer>> graph, int from, int to) {
133+
graph.get(from).add(to);
134+
graph.get(to).add(from);
135+
}
136+
}

src/main/java/com/williamfiset/algorithms/graphtheory/ConnectedComponentsDfsSolverAdjacencyList.java

Lines changed: 0 additions & 113 deletions
This file was deleted.

0 commit comments

Comments
 (0)