---
Graph$Node.class | Bin 378 -> 0 bytes
Graph.class | Bin 2251 -> 0 bytes
Main.class | Bin 658 -> 0 bytes
.../graphs/BreadthFirstSearch.java | 182 ++++++++++++++++++
.../graphs/BreadthFirstSearchTest.java | 171 ++++++++++++++++
5 files changed, 353 insertions(+)
delete mode 100644 Graph$Node.class
delete mode 100644 Graph.class
delete mode 100644 Main.class
create mode 100644 src/main/java/com/thealgorithms/datastructures/graphs/BreadthFirstSearch.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/BreadthFirstSearchTest.java
diff --git a/Graph$Node.class b/Graph$Node.class
deleted file mode 100644
index 282ca71af0ce7587ca2b904f4e5a5f5a7ba74e96..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 378
zcmZWlyH3ME5S;TPeqiEYAmLR|P$Who1to}rNPwkailFr8f)C)M
z5PNPYD0X)5ZgzI|zJETy0Nmo(hXK=p6~IP|p|j*~e3)~!7(Qi7F{>F`*HX#)hQaI)
zrXE~)4*URH2pIhPlE1#3rNvw@SaVSkKN|mOOzKjq#g*=A2ME#8EU8&6Vd(b%QQQFW<*M!&@$VDb3|PJFV#_IpFzC5&JZwh2Rc
bB+#Z-6MJ-LU?1Hk_i#wrCrKAQ9Krns@RUPM
diff --git a/Graph.class b/Graph.class
deleted file mode 100644
index e02400bb827778abb36635c1349f2704936b19e2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2251
zcmaJ?-%}G;6#g~|SrQfqL9|h^pgZsI5>zYCvr)5$&%fxxzx&O?Nja{oSYb
z59mYXp);Ln$7gK^i_CPK>5LEki~3USce9}clj&r#d-vRPzVn@PzkBar&mR8)U;^KS
z;e%gAKtmIP3L-1|x}GZP=2Gg);)=+-3WDQ?X}ISV_y>pPRWvK;s5q5fqnNs+JIk|r
zDGU|<5L%$AXw}e$b_Gq-wq9Chm|j>>(3zch2fcs_
zm8@$U=2CiQXgm2sR2FPwiEI8X$i|REaJ#z%LUukH!_CfhS3YZMC;cufLDlKDwEr2
z1C*M|c5&-X5^6|890@`#2|^7tfEua~RB=*4+a5znt_4Y?G`uRStt`rd>u%k?Eo=#ulD>!K<4p~3;evud
z$to6!KG=}=2E
z7x1Bmk1Aa@X$WyM=^7T1XWI+HA*X1KSpKVN7(&Bsxs=Vj@>dYb8cU|`mTj)*MK7v$
zyN}lc)i_D1jMwhJ^XcB9ezc-%I@RVHp9Ad9(0o&@xP$!gojf5tMjt2kOEj
zgnmW%K_z&F&o=n^3^Guqf}0WIVZT}pPZLVc9*OTDvXD6X2+`lsm5?9t>c@*fU1-HY
z941Iu-WpY)MZ!zIBM%YYLTnSQ9K^TKy@{wC?Vy*$PHdqs=S>VgK{Bz8Q$FNm1|KBV
zC{aM{PF^g>(Ty`Wh9WJ*?rbCRHDtYfN)IDc&ivx#yNAGo9Sk$YnamDG_(oz3Ig-
z;|WG*ym|5BH}L5ADIDJ=)8T+Q?Edz7-+kZb-N}!?U%mlwF>j&(&46y9h%tupe)KL{
zJc!c4VyC|!?+zKpmXkCYt}tj$t!IEU6q{M}_KgVx8pjnnH@v`aag0-Pd#mlrmWoYU
zD8nWxNsr@<3OP=2QN26Nl60_iS!vaJ99J3i^{vq3n4-STj^wz;P;zD1ltE{M^y_r=
zw;SGubY+9%Cc{Lp)%E3?FW2Q}DBBz}3`X7e!Z7zUYhey|sGPgnWtjSp88zNL>fDZ!
zl(zcOUd%8VBxxL;9QNaEGwL6Zq92~etIp14_q85_**!YRcH`AVC6`pO$7*isewQ9w
zeQKrW2E%=#8QPgr=1;*s6EHlWRfU0PDB&R<5v$an(9SP^{0d|H6s2I{l`w^6YroDg
zL2L<8-pf&lij7Y>SB0?I_nb{)eQw0lw!W704KZ!w_bA`AwLdxE5>>nKdc>w(tmJH-
z;r4~uCm1JtOW;^W1P1IO_29!-3JPh&ZBuYlS=Ks
+ * BFS is a graph traversal algorithm that explores all vertices at the present
+ * depth level before moving on to vertices at the next depth level. It uses a
+ * queue
+ * data structure to keep track of vertices to visit.
+ *
+ *
+ * Time Complexity: O(V + E) where V is the number of vertices and E is the
+ * number of edges.
+ * Space Complexity: O(V) for the visited set and queue.
+ *
+ *
+ * References:
+ *
+ * - https://en.wikipedia.org/wiki/Breadth-first_search
+ *
+ *
+ * @author Divyansh1802
+ * @author prashantdubeypng (fixes and refactoring)
+ */
+public final class BreadthFirstSearch {
+
+ private BreadthFirstSearch() {
+ // Utility class; do not instantiate.
+ }
+
+ /**
+ * Performs BFS traversal on a graph represented as an adjacency list.
+ *
+ * @param adjacencyList the graph represented as a map from vertex to list of
+ * neighbors
+ * @param source the starting vertex for traversal
+ * @param the type of vertices in the graph
+ * @return a list of vertices in BFS order starting from the source
+ * @throws IllegalArgumentException if source is null or not in the graph
+ */
+ public static List bfs(Map> adjacencyList, T source) {
+ if (source == null) {
+ throw new IllegalArgumentException("Source vertex cannot be null");
+ }
+ if (adjacencyList == null || !adjacencyList.containsKey(source)) {
+ throw new IllegalArgumentException("Source vertex must exist in the graph");
+ }
+
+ List result = new ArrayList<>();
+ Set visited = new HashSet<>();
+ Queue queue = new LinkedList<>();
+
+ queue.offer(source);
+ visited.add(source);
+
+ while (!queue.isEmpty()) {
+ T current = queue.poll();
+ result.add(current);
+
+ List neighbors = adjacencyList.get(current);
+ if (neighbors != null) {
+ for (T neighbor : neighbors) {
+ if (!visited.contains(neighbor)) {
+ visited.add(neighbor);
+ queue.offer(neighbor);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Performs BFS traversal on a graph represented using integer vertices.
+ *
+ * @param adjacencyList the graph represented as a list of lists of neighbors
+ * @param numVertices the number of vertices in the graph
+ * @param source the starting vertex for traversal (0-indexed)
+ * @return a list of vertices in BFS order starting from the source
+ * @throws IllegalArgumentException if source is out of bounds
+ */
+ public static List bfs(List> adjacencyList, int numVertices, int source) {
+ if (source < 0 || source >= numVertices) {
+ throw new IllegalArgumentException("Source vertex is out of bounds");
+ }
+ if (adjacencyList == null) {
+ throw new IllegalArgumentException("Adjacency list cannot be null");
+ }
+
+ List result = new ArrayList<>();
+ boolean[] visited = new boolean[numVertices];
+ Queue queue = new LinkedList<>();
+
+ queue.offer(source);
+ visited[source] = true;
+
+ while (!queue.isEmpty()) {
+ int current = queue.poll();
+ result.add(current);
+
+ if (current < adjacencyList.size()) {
+ List neighbors = adjacencyList.get(current);
+ if (neighbors != null) {
+ for (int neighbor : neighbors) {
+ if (neighbor >= 0 && neighbor < numVertices && !visited[neighbor]) {
+ visited[neighbor] = true;
+ queue.offer(neighbor);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates an adjacency list graph from edges.
+ *
+ * @param numVertices the number of vertices
+ * @param edges array of edges where each edge is {from, to}
+ * @param undirected if true, adds edges in both directions
+ * @return the adjacency list representation of the graph
+ */
+ public static List> createGraph(int numVertices, int[][] edges, boolean undirected) {
+ List> graph = new ArrayList<>();
+ for (int i = 0; i < numVertices; i++) {
+ graph.add(new ArrayList<>());
+ }
+
+ for (int[] edge : edges) {
+ if (edge.length >= 2) {
+ int from = edge[0];
+ int to = edge[1];
+ if (from >= 0 && from < numVertices && to >= 0 && to < numVertices) {
+ graph.get(from).add(to);
+ if (undirected) {
+ graph.get(to).add(from);
+ }
+ }
+ }
+ }
+
+ return graph;
+ }
+
+ /**
+ * Creates a Map-based adjacency list from string vertices.
+ *
+ * @param edges array of edges where each edge is {from, to}
+ * @param undirected if true, adds edges in both directions
+ * @return the adjacency list representation as a Map
+ */
+ public static Map> createStringGraph(String[][] edges, boolean undirected) {
+ Map> graph = new HashMap<>();
+
+ for (String[] edge : edges) {
+ if (edge.length >= 2) {
+ String from = edge[0];
+ String to = edge[1];
+
+ graph.computeIfAbsent(from, k -> new ArrayList<>()).add(to);
+ if (undirected) {
+ graph.computeIfAbsent(to, k -> new ArrayList<>()).add(from);
+ }
+ }
+ }
+
+ return graph;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/BreadthFirstSearchTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/BreadthFirstSearchTest.java
new file mode 100644
index 000000000000..ffbc523d0466
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/BreadthFirstSearchTest.java
@@ -0,0 +1,171 @@
+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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link BreadthFirstSearch}.
+ */
+class BreadthFirstSearchTest {
+
+ @Test
+ void testBfsWithIntegerGraphSimple() {
+ // Create a simple graph: 0 -> 1 -> 2
+ // | |
+ // v v
+ // 3 4
+ int[][] edges = { { 0, 1 }, { 0, 3 }, { 1, 2 }, { 1, 4 } };
+ List> graph = BreadthFirstSearch.createGraph(5, edges, false);
+
+ List result = BreadthFirstSearch.bfs(graph, 5, 0);
+
+ assertEquals(5, result.size());
+ assertEquals(0, result.get(0)); // Source is first
+ // BFS visits by level: 0 -> [1, 3] -> [2, 4]
+ assertTrue(result.indexOf(1) < result.indexOf(2)); // 1 before 2
+ assertTrue(result.indexOf(1) < result.indexOf(4)); // 1 before 4
+ }
+
+ @Test
+ void testBfsWithUndirectedGraph() {
+ // Create an undirected graph
+ int[][] edges = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 } };
+ List> graph = BreadthFirstSearch.createGraph(5, edges, true);
+
+ List result = BreadthFirstSearch.bfs(graph, 5, 2);
+
+ assertEquals(5, result.size());
+ assertEquals(2, result.get(0)); // Source is first
+ }
+
+ @Test
+ void testBfsWithDisconnectedGraph() {
+ // Graph with disconnected components: 0 -> 1, 2 -> 3 (separate components)
+ int[][] edges = { { 0, 1 }, { 2, 3 } };
+ List> graph = BreadthFirstSearch.createGraph(4, edges, false);
+
+ List result = BreadthFirstSearch.bfs(graph, 4, 0);
+
+ // Should only visit reachable vertices from 0
+ assertEquals(2, result.size());
+ assertTrue(result.contains(0));
+ assertTrue(result.contains(1));
+ }
+
+ @Test
+ void testBfsWithSingleVertex() {
+ int[][] edges = {};
+ List> graph = BreadthFirstSearch.createGraph(1, edges, false);
+
+ List result = BreadthFirstSearch.bfs(graph, 1, 0);
+
+ assertEquals(1, result.size());
+ assertEquals(0, result.get(0));
+ }
+
+ @Test
+ void testBfsWithCyclicGraph() {
+ // Graph with a cycle: 0 -> 1 -> 2 -> 0
+ int[][] edges = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
+ List> graph = BreadthFirstSearch.createGraph(3, edges, false);
+
+ List result = BreadthFirstSearch.bfs(graph, 3, 0);
+
+ assertEquals(3, result.size());
+ assertEquals(0, result.get(0)); // Source is first
+ }
+
+ @Test
+ void testBfsWithMapBasedGraph() {
+ Map> graph = new HashMap<>();
+ graph.put("A", List.of("B", "C"));
+ graph.put("B", List.of("D"));
+ graph.put("C", List.of("E"));
+ graph.put("D", new ArrayList<>());
+ graph.put("E", new ArrayList<>());
+
+ List result = BreadthFirstSearch.bfs(graph, "A");
+
+ assertEquals(5, result.size());
+ assertEquals("A", result.get(0)); // Source is first
+ // B and C should come before D and E
+ assertTrue(result.indexOf("B") < result.indexOf("D"));
+ assertTrue(result.indexOf("C") < result.indexOf("E"));
+ }
+
+ @Test
+ void testBfsWithStringGraphCreation() {
+ String[][] edges = { { "DELHI", "MUMBAI" }, { "DELHI", "PUNE" }, { "MUMBAI", "GOA" } };
+ Map> graph = BreadthFirstSearch.createStringGraph(edges, true);
+
+ List result = BreadthFirstSearch.bfs(graph, "DELHI");
+
+ assertEquals(4, result.size());
+ assertEquals("DELHI", result.get(0));
+ }
+
+ @Test
+ void testBfsThrowsExceptionForNullSource() {
+ Map> graph = new HashMap<>();
+ graph.put("A", List.of("B"));
+
+ assertThrows(IllegalArgumentException.class, () -> BreadthFirstSearch.bfs(graph, null));
+ }
+
+ @Test
+ void testBfsThrowsExceptionForSourceNotInGraph() {
+ Map> graph = new HashMap<>();
+ graph.put("A", List.of("B"));
+
+ assertThrows(IllegalArgumentException.class, () -> BreadthFirstSearch.bfs(graph, "X"));
+ }
+
+ @Test
+ void testBfsThrowsExceptionForInvalidSourceIndex() {
+ List> graph = BreadthFirstSearch.createGraph(3, new int[][] {}, false);
+
+ assertThrows(IllegalArgumentException.class, () -> BreadthFirstSearch.bfs(graph, 3, -1));
+ assertThrows(IllegalArgumentException.class, () -> BreadthFirstSearch.bfs(graph, 3, 5));
+ }
+
+ @Test
+ void testBfsLevelOrderProperty() {
+ // Test that BFS visits vertices level by level
+ // 0
+ // /|\
+ // 1 2 3
+ // | |
+ // 4 5
+ int[][] edges = { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 4 }, { 3, 5 } };
+ List> graph = BreadthFirstSearch.createGraph(6, edges, false);
+
+ List result = BreadthFirstSearch.bfs(graph, 6, 0);
+
+ // Level 0: 0
+ // Level 1: 1, 2, 3
+ // Level 2: 4, 5
+ assertEquals(0, result.get(0));
+ // All level-1 vertices come before level-2 vertices
+ int level1End = Math.max(result.indexOf(1), Math.max(result.indexOf(2), result.indexOf(3)));
+ int level2Start = Math.min(result.indexOf(4), result.indexOf(5));
+ assertTrue(level1End < level2Start);
+ }
+
+ @Test
+ void testBfsWithEmptyNeighborList() {
+ Map> graph = new HashMap<>();
+ graph.put("A", new ArrayList<>());
+
+ List result = BreadthFirstSearch.bfs(graph, "A");
+
+ assertEquals(1, result.size());
+ assertEquals("A", result.get(0));
+ }
+}