Skip to content

Commit 1af3d22

Browse files
committed
feat: add Articulation Points and Bridges algorithm
Implement DFS-based algorithm to find articulation points (cut vertices) and bridges (cut edges) in undirected graphs. Features: - Find articulation points: vertices whose removal increases connected components - Find bridges: edges whose removal increases connected components - Time complexity: O(V + E) using single DFS traversal - Handles disconnected graphs - Comprehensive test suite with 15 test cases Implementation details: - Uses discovery time and low-link values - Follows Tarjan's approach for graph analysis - Includes convenience methods for finding only points or only bridges - Full Javadoc documentation with examples and applications Test coverage: - Simple graphs with single/multiple articulation points - Graphs with no articulation points (biconnected components) - Star graphs, disconnected graphs, edge cases - Validates edge symmetry and proper error handling Applications: Network reliability, social network analysis, circuit design, transportation networks
1 parent 9f985b2 commit 1af3d22

File tree

2 files changed

+641
-0
lines changed

2 files changed

+641
-0
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Set;
7+
8+
/**
9+
* Java program that implements an algorithm to find Articulation Points (Cut Vertices) and Bridges (Cut Edges)
10+
* in an undirected graph using Depth-First Search (DFS).
11+
*
12+
* <p>
13+
* <b>Articulation Point (Cut Vertex):</b> A vertex in a graph whose removal increases the number of connected components.
14+
* In other words, removing an articulation point disconnects the graph or increases the number of separate subgraphs.
15+
*
16+
* <p>
17+
* <b>Bridge (Cut Edge):</b> An edge in a graph whose removal increases the number of connected components.
18+
* Bridges are critical connections in the graph.
19+
*
20+
* <h3>Algorithm Overview:</h3>
21+
* <ul>
22+
* <li><b>DFS Search:</b> A depth-first search is performed on the graph to build a DFS tree.</li>
23+
* <li><b>Discovery Time:</b> The time at which a vertex is first visited during DFS.</li>
24+
* <li><b>Low-Link Value:</b> The minimum discovery time reachable from the vertex's DFS subtree.</li>
25+
* <li><b>Articulation Point Detection:</b>
26+
* <ul>
27+
* <li>For the root: It's an articulation point if it has more than one child in the DFS tree.</li>
28+
* <li>For non-root vertices: A vertex u is an articulation point if it has a child v such that
29+
* no vertex in the subtree rooted at v has a back edge to an ancestor of u (i.e., low[v] >= discovery[u]).</li>
30+
* </ul>
31+
* </li>
32+
* <li><b>Bridge Detection:</b> An edge (u, v) is a bridge if there is no back edge from the subtree rooted at v
33+
* that goes to an ancestor of u (i.e., low[v] > discovery[u]).</li>
34+
* </ul>
35+
*
36+
* <p>
37+
* <b>Time Complexity:</b> O(V + E), where V is the number of vertices and E is the number of edges.
38+
* <br>
39+
* <b>Space Complexity:</b> O(V) for storing discovery times, low-link values, and visited status.
40+
*
41+
* <p>
42+
* Example of an undirected graph:
43+
* <pre>
44+
* 0 -------- 1 -------- 2
45+
* | |
46+
* | |
47+
* 3 -------- 4
48+
* </pre>
49+
*
50+
* <p>
51+
* For the above graph:
52+
* <ul>
53+
* <li><b>Articulation Points:</b> 1 (removing it disconnects the graph)</li>
54+
* <li><b>Bridges:</b> (0,1), (1,2), (1,4)</li>
55+
* </ul>
56+
*
57+
* <h3>Applications:</h3>
58+
* <ul>
59+
* <li>Network reliability analysis (finding critical routers/connections)</li>
60+
* <li>Social network analysis (finding influential people)</li>
61+
* <li>Circuit design (identifying critical components)</li>
62+
* <li>Transportation networks (finding critical roads/bridges)</li>
63+
* </ul>
64+
*
65+
* @see <a href="https://en.wikipedia.org/wiki/Biconnected_component">Biconnected Component on Wikipedia</a>
66+
* @see <a href="https://cp-algorithms.com/graph/bridge-searching.html">Bridge Finding Algorithm</a>
67+
*/
68+
public final class ArticulationPointsAndBridges {
69+
70+
// Represents an edge in the graph
71+
public static class Edge {
72+
private final int from;
73+
private final int to;
74+
75+
public Edge(int from, int to) {
76+
this.from = from;
77+
this.to = to;
78+
}
79+
80+
public int getFrom() {
81+
return from;
82+
}
83+
84+
public int getTo() {
85+
return to;
86+
}
87+
88+
@Override
89+
public boolean equals(Object o) {
90+
if (this == o) {
91+
return true;
92+
}
93+
if (o == null || getClass() != o.getClass()) {
94+
return false;
95+
}
96+
Edge edge = (Edge) o;
97+
return (from == edge.from && to == edge.to) || (from == edge.to && to == edge.from);
98+
}
99+
100+
@Override
101+
public int hashCode() {
102+
// Ensure edges (u,v) and (v,u) have the same hash code
103+
return Math.min(from, to) * 31 + Math.max(from, to);
104+
}
105+
106+
@Override
107+
public String toString() {
108+
return "(" + from + ", " + to + ")";
109+
}
110+
}
111+
112+
// Result class to hold both articulation points and bridges
113+
public static class Result {
114+
private final Set<Integer> articulationPoints;
115+
private final Set<Edge> bridges;
116+
117+
public Result(Set<Integer> articulationPoints, Set<Edge> bridges) {
118+
this.articulationPoints = articulationPoints;
119+
this.bridges = bridges;
120+
}
121+
122+
public Set<Integer> getArticulationPoints() {
123+
return articulationPoints;
124+
}
125+
126+
public Set<Edge> getBridges() {
127+
return bridges;
128+
}
129+
130+
@Override
131+
public String toString() {
132+
return "Articulation Points: " + articulationPoints + ", Bridges: " + bridges;
133+
}
134+
}
135+
136+
private ArticulationPointsAndBridges() {
137+
}
138+
139+
// Timer for tracking discovery time
140+
private static int time;
141+
142+
/**
143+
* Finds articulation points and bridges in an undirected graph.
144+
*
145+
* @param vertices the number of vertices in the graph
146+
* @param graph the adjacency list representation of the graph
147+
* @return a Result object containing sets of articulation points and bridges
148+
* @throws IllegalArgumentException if vertices is negative or if graph is null
149+
*/
150+
public static Result findArticulationPointsAndBridges(int vertices, List<List<Integer>> graph) {
151+
if (vertices < 0) {
152+
throw new IllegalArgumentException("Number of vertices cannot be negative");
153+
}
154+
if (graph == null) {
155+
throw new IllegalArgumentException("Graph cannot be null");
156+
}
157+
158+
// Initialize data structures
159+
int[] discoveryTime = new int[vertices];
160+
int[] lowLink = new int[vertices];
161+
boolean[] visited = new boolean[vertices];
162+
int[] parent = new int[vertices];
163+
164+
Set<Integer> articulationPoints = new HashSet<>();
165+
Set<Edge> bridges = new HashSet<>();
166+
167+
// Initialize arrays
168+
for (int i = 0; i < vertices; i++) {
169+
discoveryTime[i] = -1;
170+
lowLink[i] = -1;
171+
parent[i] = -1;
172+
}
173+
174+
time = 0;
175+
176+
// Perform DFS from each unvisited vertex (handles disconnected graphs)
177+
for (int i = 0; i < vertices; i++) {
178+
if (!visited[i]) {
179+
dfs(i, visited, discoveryTime, lowLink, parent, articulationPoints, bridges, graph);
180+
}
181+
}
182+
183+
return new Result(articulationPoints, bridges);
184+
}
185+
186+
/**
187+
* Depth-First Search utility function to find articulation points and bridges.
188+
*
189+
* @param u the current vertex being visited
190+
* @param visited array tracking visited vertices
191+
* @param discoveryTime array storing discovery time of each vertex
192+
* @param lowLink array storing low-link values
193+
* @param parent array storing parent of each vertex in DFS tree
194+
* @param articulationPoints set to store articulation points
195+
* @param bridges set to store bridges
196+
* @param graph the adjacency list representation of the graph
197+
*/
198+
private static void dfs(int u, boolean[] visited, int[] discoveryTime, int[] lowLink, int[] parent, Set<Integer> articulationPoints, Set<Edge> bridges, List<List<Integer>> graph) {
199+
// Count children in DFS tree (used for root articulation point check)
200+
int children = 0;
201+
202+
// Mark the current vertex as visited
203+
visited[u] = true;
204+
205+
// Set discovery time and low-link value
206+
discoveryTime[u] = time;
207+
lowLink[u] = time;
208+
time++;
209+
210+
// Explore all adjacent vertices
211+
for (Integer v : graph.get(u)) {
212+
// If v is not visited, make it a child of u in DFS tree and recur
213+
if (!visited[v]) {
214+
children++;
215+
parent[v] = u;
216+
dfs(v, visited, discoveryTime, lowLink, parent, articulationPoints, bridges, graph);
217+
218+
// Check if the subtree rooted at v has a connection back to an ancestor of u
219+
lowLink[u] = Math.min(lowLink[u], lowLink[v]);
220+
221+
// Articulation point check for non-root vertex
222+
// If u is not root and low-link value of v is greater than or equal to discovery time of u
223+
if (parent[u] != -1 && lowLink[v] >= discoveryTime[u]) {
224+
articulationPoints.add(u);
225+
}
226+
227+
// Bridge check
228+
// If low-link value of v is greater than discovery time of u, then (u,v) is a bridge
229+
if (lowLink[v] > discoveryTime[u]) {
230+
bridges.add(new Edge(u, v));
231+
}
232+
} else if (v != parent[u]) {
233+
// Update low-link value of u for back edge (v is visited and not parent of u)
234+
lowLink[u] = Math.min(lowLink[u], discoveryTime[v]);
235+
}
236+
}
237+
238+
// Articulation point check for root vertex
239+
// If u is root of DFS tree and has more than one child, it's an articulation point
240+
if (parent[u] == -1 && children > 1) {
241+
articulationPoints.add(u);
242+
}
243+
}
244+
245+
/**
246+
* Convenience method to find only articulation points.
247+
*
248+
* @param vertices the number of vertices in the graph
249+
* @param graph the adjacency list representation of the graph
250+
* @return a set of articulation points
251+
* @throws IllegalArgumentException if vertices is negative or if graph is null
252+
*/
253+
public static Set<Integer> findArticulationPoints(int vertices, List<List<Integer>> graph) {
254+
return findArticulationPointsAndBridges(vertices, graph).getArticulationPoints();
255+
}
256+
257+
/**
258+
* Convenience method to find only bridges.
259+
*
260+
* @param vertices the number of vertices in the graph
261+
* @param graph the adjacency list representation of the graph
262+
* @return a set of bridges
263+
* @throws IllegalArgumentException if vertices is negative or if graph is null
264+
*/
265+
public static Set<Edge> findBridges(int vertices, List<List<Integer>> graph) {
266+
return findArticulationPointsAndBridges(vertices, graph).getBridges();
267+
}
268+
}

0 commit comments

Comments
 (0)