diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridges.java b/src/main/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridges.java
new file mode 100644
index 000000000000..b1eb718ea6c0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridges.java
@@ -0,0 +1,268 @@
+package com.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Java program that implements an algorithm to find Articulation Points (Cut Vertices) and Bridges (Cut Edges)
+ * in an undirected graph using Depth-First Search (DFS).
+ *
+ *
+ * Articulation Point (Cut Vertex): A vertex in a graph whose removal increases the number of connected components.
+ * In other words, removing an articulation point disconnects the graph or increases the number of separate subgraphs.
+ *
+ *
+ * Bridge (Cut Edge): An edge in a graph whose removal increases the number of connected components.
+ * Bridges are critical connections in the graph.
+ *
+ *
Algorithm Overview:
+ *
+ * - DFS Search: A depth-first search is performed on the graph to build a DFS tree.
+ * - Discovery Time: The time at which a vertex is first visited during DFS.
+ * - Low-Link Value: The minimum discovery time reachable from the vertex's DFS subtree.
+ * - Articulation Point Detection:
+ *
+ * - For the root: It's an articulation point if it has more than one child in the DFS tree.
+ * - For non-root vertices: A vertex u is an articulation point if it has a child v such that
+ * no vertex in the subtree rooted at v has a back edge to an ancestor of u (i.e., low[v] >= discovery[u]).
+ *
+ *
+ * - Bridge Detection: An edge (u, v) is a bridge if there is no back edge from the subtree rooted at v
+ * that goes to an ancestor of u (i.e., low[v] > discovery[u]).
+ *
+ *
+ *
+ * Time Complexity: O(V + E), where V is the number of vertices and E is the number of edges.
+ *
+ * Space Complexity: O(V) for storing discovery times, low-link values, and visited status.
+ *
+ *
+ * Example of an undirected graph:
+ *
+ * 0 -------- 1 -------- 2
+ * | |
+ * | |
+ * 3 -------- 4
+ *
+ *
+ *
+ * For the above graph:
+ *
+ * - Articulation Points: 1 (removing it disconnects the graph)
+ * - Bridges: (0,1), (1,2), (1,4)
+ *
+ *
+ * Applications:
+ *
+ * - Network reliability analysis (finding critical routers/connections)
+ * - Social network analysis (finding influential people)
+ * - Circuit design (identifying critical components)
+ * - Transportation networks (finding critical roads/bridges)
+ *
+ *
+ * @see Biconnected Component on Wikipedia
+ * @see Bridge Finding Algorithm
+ */
+public final class ArticulationPointsAndBridges {
+
+ // Represents an edge in the graph
+ public static class Edge {
+ private final int from;
+ private final int to;
+
+ public Edge(int from, int to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ public int getFrom() {
+ return from;
+ }
+
+ public int getTo() {
+ return to;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Edge edge = (Edge) o;
+ return (from == edge.from && to == edge.to) || (from == edge.to && to == edge.from);
+ }
+
+ @Override
+ public int hashCode() {
+ // Ensure edges (u,v) and (v,u) have the same hash code
+ return Math.min(from, to) * 31 + Math.max(from, to);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + from + ", " + to + ")";
+ }
+ }
+
+ // Result class to hold both articulation points and bridges
+ public static class Result {
+ private final Set articulationPoints;
+ private final Set bridges;
+
+ public Result(Set articulationPoints, Set bridges) {
+ this.articulationPoints = articulationPoints;
+ this.bridges = bridges;
+ }
+
+ public Set getArticulationPoints() {
+ return articulationPoints;
+ }
+
+ public Set getBridges() {
+ return bridges;
+ }
+
+ @Override
+ public String toString() {
+ return "Articulation Points: " + articulationPoints + ", Bridges: " + bridges;
+ }
+ }
+
+ private ArticulationPointsAndBridges() {
+ }
+
+ // Timer for tracking discovery time
+ private static int time;
+
+ /**
+ * Finds articulation points and bridges in an undirected graph.
+ *
+ * @param vertices the number of vertices in the graph
+ * @param graph the adjacency list representation of the graph
+ * @return a Result object containing sets of articulation points and bridges
+ * @throws IllegalArgumentException if vertices is negative or if graph is null
+ */
+ public static Result findArticulationPointsAndBridges(int vertices, List> graph) {
+ if (vertices < 0) {
+ throw new IllegalArgumentException("Number of vertices cannot be negative");
+ }
+ if (graph == null) {
+ throw new IllegalArgumentException("Graph cannot be null");
+ }
+
+ // Initialize data structures
+ int[] discoveryTime = new int[vertices];
+ int[] lowLink = new int[vertices];
+ boolean[] visited = new boolean[vertices];
+ int[] parent = new int[vertices];
+
+ Set articulationPoints = new HashSet<>();
+ Set bridges = new HashSet<>();
+
+ // Initialize arrays
+ for (int i = 0; i < vertices; i++) {
+ discoveryTime[i] = -1;
+ lowLink[i] = -1;
+ parent[i] = -1;
+ }
+
+ time = 0;
+
+ // Perform DFS from each unvisited vertex (handles disconnected graphs)
+ for (int i = 0; i < vertices; i++) {
+ if (!visited[i]) {
+ dfs(i, visited, discoveryTime, lowLink, parent, articulationPoints, bridges, graph);
+ }
+ }
+
+ return new Result(articulationPoints, bridges);
+ }
+
+ /**
+ * Depth-First Search utility function to find articulation points and bridges.
+ *
+ * @param u the current vertex being visited
+ * @param visited array tracking visited vertices
+ * @param discoveryTime array storing discovery time of each vertex
+ * @param lowLink array storing low-link values
+ * @param parent array storing parent of each vertex in DFS tree
+ * @param articulationPoints set to store articulation points
+ * @param bridges set to store bridges
+ * @param graph the adjacency list representation of the graph
+ */
+ private static void dfs(int u, boolean[] visited, int[] discoveryTime, int[] lowLink, int[] parent, Set articulationPoints, Set bridges, List> graph) {
+ // Count children in DFS tree (used for root articulation point check)
+ int children = 0;
+
+ // Mark the current vertex as visited
+ visited[u] = true;
+
+ // Set discovery time and low-link value
+ discoveryTime[u] = time;
+ lowLink[u] = time;
+ time++;
+
+ // Explore all adjacent vertices
+ for (Integer v : graph.get(u)) {
+ // If v is not visited, make it a child of u in DFS tree and recur
+ if (!visited[v]) {
+ children++;
+ parent[v] = u;
+ dfs(v, visited, discoveryTime, lowLink, parent, articulationPoints, bridges, graph);
+
+ // Check if the subtree rooted at v has a connection back to an ancestor of u
+ lowLink[u] = Math.min(lowLink[u], lowLink[v]);
+
+ // Articulation point check for non-root vertex
+ // If u is not root and low-link value of v is greater than or equal to discovery time of u
+ if (parent[u] != -1 && lowLink[v] >= discoveryTime[u]) {
+ articulationPoints.add(u);
+ }
+
+ // Bridge check
+ // If low-link value of v is greater than discovery time of u, then (u,v) is a bridge
+ if (lowLink[v] > discoveryTime[u]) {
+ bridges.add(new Edge(u, v));
+ }
+ } else if (v != parent[u]) {
+ // Update low-link value of u for back edge (v is visited and not parent of u)
+ lowLink[u] = Math.min(lowLink[u], discoveryTime[v]);
+ }
+ }
+
+ // Articulation point check for root vertex
+ // If u is root of DFS tree and has more than one child, it's an articulation point
+ if (parent[u] == -1 && children > 1) {
+ articulationPoints.add(u);
+ }
+ }
+
+ /**
+ * Convenience method to find only articulation points.
+ *
+ * @param vertices the number of vertices in the graph
+ * @param graph the adjacency list representation of the graph
+ * @return a set of articulation points
+ * @throws IllegalArgumentException if vertices is negative or if graph is null
+ */
+ public static Set findArticulationPoints(int vertices, List> graph) {
+ return findArticulationPointsAndBridges(vertices, graph).getArticulationPoints();
+ }
+
+ /**
+ * Convenience method to find only bridges.
+ *
+ * @param vertices the number of vertices in the graph
+ * @param graph the adjacency list representation of the graph
+ * @return a set of bridges
+ * @throws IllegalArgumentException if vertices is negative or if graph is null
+ */
+ public static Set findBridges(int vertices, List> graph) {
+ return findArticulationPointsAndBridges(vertices, graph).getBridges();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridgesTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridgesTest.java
new file mode 100644
index 000000000000..6d4b108f4fe0
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/ArticulationPointsAndBridgesTest.java
@@ -0,0 +1,373 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.thealgorithms.datastructures.graphs.ArticulationPointsAndBridges.Edge;
+import com.thealgorithms.datastructures.graphs.ArticulationPointsAndBridges.Result;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+
+public class ArticulationPointsAndBridgesTest {
+
+ /**
+ * Helper method to create an undirected graph adjacency list.
+ */
+ private List> createGraph(int vertices) {
+ List> graph = new ArrayList<>();
+ for (int i = 0; i < vertices; i++) {
+ graph.add(new ArrayList<>());
+ }
+ return graph;
+ }
+
+ /**
+ * Helper method to add an undirected edge to the graph.
+ */
+ private void addEdge(List> graph, int u, int v) {
+ graph.get(u).add(v);
+ graph.get(v).add(u);
+ }
+
+ @Test
+ public void testSimpleGraphWithOneArticulationPoint() {
+ /*
+ * Graph structure:
+ * 0 -------- 1 -------- 2
+ * | |
+ * | |
+ * 3 -------- 4
+ *
+ * Articulation Point: 1
+ * Bridges: (0,1), (1,2), (1,4)
+ */
+ int vertices = 5;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 0, 3);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 1, 4);
+ addEdge(graph, 3, 4);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(1, articulationPoints.size());
+ assertTrue(articulationPoints.contains(1));
+
+ // Verify bridges
+ Set bridges = result.getBridges();
+ assertEquals(2, bridges.size());
+ assertTrue(bridges.contains(new Edge(1, 2)));
+ assertTrue(bridges.contains(new Edge(0, 1)));
+ }
+
+ @Test
+ public void testGraphWithMultipleArticulationPoints() {
+ /*
+ * Graph structure:
+ * 0 -------- 1 -------- 2 -------- 3
+ *
+ * Articulation Points: 1, 2
+ * Bridges: (0,1), (1,2), (2,3)
+ */
+ int vertices = 4;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 3);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(2, articulationPoints.size());
+ assertTrue(articulationPoints.contains(1));
+ assertTrue(articulationPoints.contains(2));
+
+ // Verify bridges
+ Set bridges = result.getBridges();
+ assertEquals(3, bridges.size());
+ assertTrue(bridges.contains(new Edge(0, 1)));
+ assertTrue(bridges.contains(new Edge(1, 2)));
+ assertTrue(bridges.contains(new Edge(2, 3)));
+ }
+
+ @Test
+ public void testGraphWithNoArticulationPoints() {
+ /*
+ * Graph structure (triangle):
+ * 0
+ * / \
+ * 1---2
+ *
+ * Articulation Points: None (it's a cycle, removing any vertex still leaves graph connected)
+ * Bridges: None
+ */
+ int vertices = 3;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 0);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify no articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(0, articulationPoints.size());
+
+ // Verify no bridges
+ Set bridges = result.getBridges();
+ assertEquals(0, bridges.size());
+ }
+
+ @Test
+ public void testComplexGraphWithArticulationPointsAndBridges() {
+ /*
+ * Graph structure:
+ * 0 -------- 1 -------- 2
+ * | / | |
+ * | / | |
+ * | / | |
+ * | / | |
+ * | / | |
+ * 3 ---------4 5
+ * | |
+ * | |
+ * 6----------7
+ *
+ * Articulation Points: 1, 2, 4, 6
+ * Bridges: (1,2), (2,5), (4,6), (5,7)
+ */
+ int vertices = 8;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 0, 3);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 1, 3);
+ addEdge(graph, 1, 4);
+ addEdge(graph, 3, 4);
+ addEdge(graph, 2, 5);
+ addEdge(graph, 4, 6);
+ addEdge(graph, 5, 7);
+ addEdge(graph, 6, 7);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(4, articulationPoints.size());
+ assertTrue(articulationPoints.contains(1));
+ assertTrue(articulationPoints.contains(2));
+ assertTrue(articulationPoints.contains(4));
+ assertTrue(articulationPoints.contains(6));
+
+ // Verify bridges
+ Set bridges = result.getBridges();
+ assertEquals(3, bridges.size());
+ assertTrue(bridges.contains(new Edge(1, 2)));
+ assertTrue(bridges.contains(new Edge(2, 5)));
+ assertTrue(bridges.contains(new Edge(4, 6)));
+ }
+
+ @Test
+ public void testDisconnectedGraph() {
+ /*
+ * Graph structure:
+ * 0 -------- 1 2 -------- 3
+ *
+ * Articulation Points: None (each component is too small)
+ * Bridges: (0,1), (2,3)
+ */
+ int vertices = 4;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 2, 3);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify no articulation points (each component has only 2 vertices)
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(0, articulationPoints.size());
+
+ // Verify bridges
+ Set bridges = result.getBridges();
+ assertEquals(2, bridges.size());
+ assertTrue(bridges.contains(new Edge(0, 1)));
+ assertTrue(bridges.contains(new Edge(2, 3)));
+ }
+
+ @Test
+ public void testStarGraph() {
+ /*
+ * Graph structure (star with center at 0):
+ * 1
+ * |
+ * 2---0---3
+ * |
+ * 4
+ *
+ * Articulation Point: 0 (center)
+ * Bridges: (0,1), (0,2), (0,3), (0,4)
+ */
+ int vertices = 5;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 0, 2);
+ addEdge(graph, 0, 3);
+ addEdge(graph, 0, 4);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify articulation point
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(1, articulationPoints.size());
+ assertTrue(articulationPoints.contains(0));
+
+ // Verify bridges (all edges are bridges in a star graph)
+ Set bridges = result.getBridges();
+ assertEquals(4, bridges.size());
+ assertTrue(bridges.contains(new Edge(0, 1)));
+ assertTrue(bridges.contains(new Edge(0, 2)));
+ assertTrue(bridges.contains(new Edge(0, 3)));
+ assertTrue(bridges.contains(new Edge(0, 4)));
+ }
+
+ @Test
+ public void testSingleVertexGraph() {
+ /*
+ * Graph with single vertex (no edges)
+ * Articulation Points: None
+ * Bridges: None
+ */
+ int vertices = 1;
+ List> graph = createGraph(vertices);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify no articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(0, articulationPoints.size());
+
+ // Verify no bridges
+ Set bridges = result.getBridges();
+ assertEquals(0, bridges.size());
+ }
+
+ @Test
+ public void testEmptyGraph() {
+ /*
+ * Empty graph (no vertices)
+ * Articulation Points: None
+ * Bridges: None
+ */
+ int vertices = 0;
+ List> graph = createGraph(vertices);
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify no articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(0, articulationPoints.size());
+
+ // Verify no bridges
+ Set bridges = result.getBridges();
+ assertEquals(0, bridges.size());
+ }
+
+ @Test
+ public void testBiconnectedGraph() {
+ /*
+ * Graph structure (square with diagonal):
+ * 0 -------- 1
+ * | \ |
+ * | \ |
+ * | \ |
+ * | \ |
+ * 3 -------- 2
+ *
+ * Articulation Points: None (biconnected - no single point of failure)
+ * Bridges: None
+ */
+ int vertices = 4;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 3);
+ addEdge(graph, 3, 0);
+ addEdge(graph, 0, 2); // Diagonal
+
+ Result result = ArticulationPointsAndBridges.findArticulationPointsAndBridges(vertices, graph);
+
+ // Verify no articulation points
+ Set articulationPoints = result.getArticulationPoints();
+ assertEquals(0, articulationPoints.size());
+
+ // Verify no bridges
+ Set bridges = result.getBridges();
+ assertEquals(0, bridges.size());
+ }
+
+ @Test
+ public void testConvenienceMethodFindArticulationPoints() {
+ int vertices = 5;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 3);
+ addEdge(graph, 3, 4);
+
+ Set articulationPoints = ArticulationPointsAndBridges.findArticulationPoints(vertices, graph);
+
+ assertEquals(3, articulationPoints.size());
+ assertTrue(articulationPoints.contains(1));
+ assertTrue(articulationPoints.contains(2));
+ assertTrue(articulationPoints.contains(3));
+ }
+
+ @Test
+ public void testConvenienceMethodFindBridges() {
+ int vertices = 3;
+ List> graph = createGraph(vertices);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+
+ Set bridges = ArticulationPointsAndBridges.findBridges(vertices, graph);
+
+ assertEquals(2, bridges.size());
+ assertTrue(bridges.contains(new Edge(0, 1)));
+ assertTrue(bridges.contains(new Edge(1, 2)));
+ }
+
+ @Test
+ public void testNegativeVerticesThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ ArticulationPointsAndBridges.findArticulationPointsAndBridges(-1, new ArrayList<>());
+ });
+ }
+
+ @Test
+ public void testNullGraphThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ ArticulationPointsAndBridges.findArticulationPointsAndBridges(5, null);
+ });
+ }
+
+ @Test
+ public void testEdgeEquality() {
+ Edge edge1 = new Edge(1, 2);
+ Edge edge2 = new Edge(2, 1);
+ Edge edge3 = new Edge(1, 3);
+
+ // Test symmetry: (1,2) should equal (2,1)
+ assertEquals(edge1, edge2);
+ assertEquals(edge1.hashCode(), edge2.hashCode());
+
+ // Test inequality
+ assertTrue(!edge1.equals(edge3));
+ }
+}