mst = kruskalMST(vertices, edges);
+
+ // Print results
+ System.out.println("Edges in the Minimum Spanning Tree:");
+ for (Edge edge : mst) {
+ System.out.println(edge);
+ }
+
+ System.out.println("\nTotal weight of MST: " + getMSTWeight(mst));
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
index 543fe2d02b50..6fc29c027eed 100644
--- a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
+++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
@@ -2,151 +2,110 @@
/**
* Sudoku Solver using Backtracking Algorithm
- * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9)
- *
- * @author Navadeep0007
+ *
+ * This class implements a backtracking algorithm to solve a 9x9 Sudoku puzzle.
+ * The algorithm systematically tries valid numbers in empty cells and backtracks
+ * when it encounters an invalid state.
+ *
+ * Time Complexity: O(9^m) where m is the number of empty cells
+ * Space Complexity: O(m) for the recursion stack
+ *
+ * @author Raghu0703
*/
public final class SudokuSolver {
-
+
private static final int GRID_SIZE = 9;
- private static final int SUBGRID_SIZE = 3;
private static final int EMPTY_CELL = 0;
private SudokuSolver() {
- // Utility class, prevent instantiation
+ // Utility class, no instantiation
}
/**
- * Solves the Sudoku puzzle using backtracking
- *
- * @param board 9x9 Sudoku board with 0 representing empty cells
- * @return true if puzzle is solved, false otherwise
+ * Checks if placing a number at a given position is valid according to Sudoku rules
+ *
+ * @param board the Sudoku board
+ * @param row the row index
+ * @param col the column index
+ * @param num the number to place
+ * @return true if the placement is valid, false otherwise
*/
- public static boolean solveSudoku(int[][] board) {
- if (board == null || board.length != GRID_SIZE) {
- return false;
+ private static boolean isValid(int[][] board, int row, int col, int num) {
+ // Check if num is already in the row
+ for (int i = 0; i < GRID_SIZE; i++) {
+ if (board[row][i] == num) {
+ return false;
+ }
}
- for (int row = 0; row < GRID_SIZE; row++) {
- if (board[row].length != GRID_SIZE) {
+ // Check if num is already in the column
+ for (int i = 0; i < GRID_SIZE; i++) {
+ if (board[i][col] == num) {
return false;
}
}
- return solve(board);
+ // Check if num is already in the 3x3 subgrid
+ int subgridRowStart = row - row % 3;
+ int subgridColStart = col - col % 3;
+ for (int i = subgridRowStart; i < subgridRowStart + 3; i++) {
+ for (int j = subgridColStart; j < subgridColStart + 3; j++) {
+ if (board[i][j] == num) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
/**
- * Recursive helper method to solve the Sudoku puzzle
- *
- * @param board the Sudoku board
- * @return true if solution is found, false otherwise
+ * Solves the Sudoku puzzle using backtracking
+ *
+ * @param board the Sudoku board (0 represents empty cells)
+ * @return true if the puzzle is solvable, false otherwise
*/
- private static boolean solve(int[][] board) {
+ public static boolean solveSudoku(int[][] board) {
for (int row = 0; row < GRID_SIZE; row++) {
for (int col = 0; col < GRID_SIZE; col++) {
+ // Find an empty cell
if (board[row][col] == EMPTY_CELL) {
- for (int number = 1; number <= GRID_SIZE; number++) {
- if (isValidPlacement(board, row, col, number)) {
- board[row][col] = number;
+ // Try numbers 1 through 9
+ for (int num = 1; num <= GRID_SIZE; num++) {
+ if (isValid(board, row, col, num)) {
+ // Place the number
+ board[row][col] = num;
- if (solve(board)) {
+ // Recursively try to solve the rest
+ if (solveSudoku(board)) {
return true;
}
- // Backtrack
+ // Backtrack: undo the placement
board[row][col] = EMPTY_CELL;
}
}
+ // No valid number found, trigger backtracking
return false;
}
}
}
+ // All cells filled successfully
return true;
}
/**
- * Checks if placing a number at given position is valid
- *
- * @param board the Sudoku board
- * @param row row index
- * @param col column index
- * @param number number to place (1-9)
- * @return true if placement is valid, false otherwise
+ * Prints the Sudoku board in a formatted manner
+ *
+ * @param board the Sudoku board to print
*/
- private static boolean isValidPlacement(int[][] board, int row, int col, int number) {
- return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number);
- }
-
- /**
- * Checks if number exists in the given row
- *
- * @param board the Sudoku board
- * @param row row index
- * @param number number to check
- * @return true if number exists in row, false otherwise
- */
- private static boolean isNumberInRow(int[][] board, int row, int number) {
- for (int col = 0; col < GRID_SIZE; col++) {
- if (board[row][col] == number) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if number exists in the given column
- *
- * @param board the Sudoku board
- * @param col column index
- * @param number number to check
- * @return true if number exists in column, false otherwise
- */
- private static boolean isNumberInColumn(int[][] board, int col, int number) {
- for (int row = 0; row < GRID_SIZE; row++) {
- if (board[row][col] == number) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if number exists in the 3x3 subgrid
- *
- * @param board the Sudoku board
- * @param row row index
- * @param col column index
- * @param number number to check
- * @return true if number exists in subgrid, false otherwise
- */
- private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) {
- int subgridRowStart = row - row % SUBGRID_SIZE;
- int subgridColStart = col - col % SUBGRID_SIZE;
-
- for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) {
- for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) {
- if (board[i][j] == number) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Prints the Sudoku board
- *
- * @param board the Sudoku board
- */
- public static void printBoard(int[][] board) {
+ private static void printBoard(int[][] board) {
for (int row = 0; row < GRID_SIZE; row++) {
- if (row % SUBGRID_SIZE == 0 && row != 0) {
+ if (row % 3 == 0 && row != 0) {
System.out.println("-----------");
}
for (int col = 0; col < GRID_SIZE; col++) {
- if (col % SUBGRID_SIZE == 0 && col != 0) {
+ if (col % 3 == 0 && col != 0) {
System.out.print("|");
}
System.out.print(board[row][col]);
@@ -154,4 +113,32 @@ public static void printBoard(int[][] board) {
System.out.println();
}
}
+
+ /**
+ * Example usage of the Sudoku Solver
+ */
+ public static void main(String[] args) {
+ // Example Sudoku puzzle (0 represents empty cells)
+ int[][] board = {
+ {5, 3, 0, 0, 7, 0, 0, 0, 0},
+ {6, 0, 0, 1, 9, 5, 0, 0, 0},
+ {0, 9, 8, 0, 0, 0, 0, 6, 0},
+ {8, 0, 0, 0, 6, 0, 0, 0, 3},
+ {4, 0, 0, 8, 0, 3, 0, 0, 1},
+ {7, 0, 0, 0, 2, 0, 0, 0, 6},
+ {0, 6, 0, 0, 0, 0, 2, 8, 0},
+ {0, 0, 0, 4, 1, 9, 0, 0, 5},
+ {0, 0, 0, 0, 8, 0, 0, 7, 9}
+ };
+
+ System.out.println("Original Sudoku Puzzle:");
+ printBoard(board);
+
+ if (solveSudoku(board)) {
+ System.out.println("\nSolved Sudoku:");
+ printBoard(board);
+ } else {
+ System.out.println("\nNo solution exists for this Sudoku puzzle.");
+ }
+ }
}
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java
new file mode 100644
index 000000000000..76c81022c553
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java
@@ -0,0 +1,159 @@
+package com.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Topological Sorting using Depth-First Search (DFS)
+ *
+ * Topological sorting for a Directed Acyclic Graph (DAG) is a linear ordering of vertices
+ * such that for every directed edge u → v, vertex u comes before v in the ordering.
+ *
+ *
This algorithm uses DFS traversal to compute the topological order. It maintains a visited
+ * set to track processed nodes and a recursion stack to detect cycles.
+ *
+ *
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 recursion stack and data structures
+ *
+ *
Applications:
+ * - Task scheduling with dependencies
+ * - Build systems (e.g., makefiles)
+ * - Course prerequisite resolution
+ * - Compilation order in software projects
+ *
+ * @author Raghu0703
+ * @see Topological Sorting
+ */
+public final class TopologicalSortDFS {
+
+ private TopologicalSortDFS() {
+ }
+
+ /**
+ * Performs topological sorting on a directed graph using DFS
+ *
+ * @param graph the adjacency list representation of the directed graph
+ * @return a list containing vertices in topological order
+ * @throws IllegalArgumentException if the graph contains a cycle
+ */
+ public static List topologicalSort(List> graph) {
+ if (graph == null || graph.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ int vertices = graph.size();
+ boolean[] visited = new boolean[vertices];
+ boolean[] recursionStack = new boolean[vertices];
+ Stack stack = new Stack<>();
+
+ // Perform DFS from all unvisited vertices
+ for (int i = 0; i < vertices; i++) {
+ if (!visited[i]) {
+ if (hasCycleDFS(graph, i, visited, recursionStack, stack)) {
+ throw new IllegalArgumentException("Graph contains a cycle. Topological sort is not possible for cyclic graphs.");
+ }
+ }
+ }
+
+ // Pop all vertices from stack to get topological order
+ List result = new ArrayList<>();
+ while (!stack.isEmpty()) {
+ result.add(stack.pop());
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper method to perform DFS and detect cycles
+ *
+ * @param graph the adjacency list representation of the graph
+ * @param vertex current vertex being processed
+ * @param visited array to track visited vertices
+ * @param recursionStack array to track vertices in current recursion path
+ * @param stack stack to store vertices in reverse topological order
+ * @return true if a cycle is detected, false otherwise
+ */
+ private static boolean hasCycleDFS(List> graph, int vertex, boolean[] visited, boolean[] recursionStack, Stack stack) {
+ // Mark current node as visited and part of recursion stack
+ visited[vertex] = true;
+ recursionStack[vertex] = true;
+
+ // Recur for all adjacent vertices
+ List neighbors = graph.get(vertex);
+ if (neighbors != null) {
+ for (Integer neighbor : neighbors) {
+ // If neighbor is not visited, recursively check for cycles
+ if (!visited[neighbor]) {
+ if (hasCycleDFS(graph, neighbor, visited, recursionStack, stack)) {
+ return true;
+ }
+ } else if (recursionStack[neighbor]) {
+ // If neighbor is in recursion stack, cycle detected
+ return true;
+ }
+ }
+ }
+
+ // Remove vertex from recursion stack and push to result stack
+ recursionStack[vertex] = false;
+ stack.push(vertex);
+ return false;
+ }
+
+ /**
+ * Checks if the given directed graph is a Directed Acyclic Graph (DAG)
+ *
+ * @param graph the adjacency list representation of the directed graph
+ * @return true if graph is a DAG, false if it contains a cycle
+ */
+ public static boolean isDAG(List> graph) {
+ if (graph == null || graph.isEmpty()) {
+ return true;
+ }
+
+ int vertices = graph.size();
+ boolean[] visited = new boolean[vertices];
+ boolean[] recursionStack = new boolean[vertices];
+
+ for (int i = 0; i < vertices; i++) {
+ if (!visited[i]) {
+ if (detectCycle(graph, i, visited, recursionStack)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Helper method to detect cycle in a directed graph
+ *
+ * @param graph the adjacency list representation of the graph
+ * @param vertex current vertex being processed
+ * @param visited array to track visited vertices
+ * @param recursionStack array to track vertices in current recursion path
+ * @return true if a cycle is detected, false otherwise
+ */
+ private static boolean detectCycle(List> graph, int vertex, boolean[] visited, boolean[] recursionStack) {
+ visited[vertex] = true;
+ recursionStack[vertex] = true;
+
+ List neighbors = graph.get(vertex);
+ if (neighbors != null) {
+ for (Integer neighbor : neighbors) {
+ if (!visited[neighbor]) {
+ if (detectCycle(graph, neighbor, visited, recursionStack)) {
+ return true;
+ }
+ } else if (recursionStack[neighbor]) {
+ return true;
+ }
+ }
+ }
+
+ recursionStack[vertex] = false;
+ return false;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
index 75d3eae08629..171ddbee809c 100644
--- a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
+++ b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
@@ -1,53 +1,138 @@
package com.thealgorithms.backtracking;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
class SudokuSolverTest {
@Test
- void testSolveSudokuEasyPuzzle() {
- int[][] board = {{5, 3, 0, 0, 7, 0, 0, 0, 0}, {6, 0, 0, 1, 9, 5, 0, 0, 0}, {0, 9, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 3}, {4, 0, 0, 8, 0, 3, 0, 0, 1}, {7, 0, 0, 0, 2, 0, 0, 0, 6}, {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, {0, 0, 0, 0, 8, 0, 0, 7, 9}};
+ void testSolvableSudoku() {
+ int[][] board = {
+ {5, 3, 0, 0, 7, 0, 0, 0, 0},
+ {6, 0, 0, 1, 9, 5, 0, 0, 0},
+ {0, 9, 8, 0, 0, 0, 0, 6, 0},
+ {8, 0, 0, 0, 6, 0, 0, 0, 3},
+ {4, 0, 0, 8, 0, 3, 0, 0, 1},
+ {7, 0, 0, 0, 2, 0, 0, 0, 6},
+ {0, 6, 0, 0, 0, 0, 2, 8, 0},
+ {0, 0, 0, 4, 1, 9, 0, 0, 5},
+ {0, 0, 0, 0, 8, 0, 0, 7, 9}
+ };
+
+ assertTrue(SudokuSolver.solveSudoku(board), "The Sudoku puzzle should be solvable");
- assertTrue(SudokuSolver.solveSudoku(board));
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ assertTrue(board[i][j] >= 1 && board[i][j] <= 9, "All cells should contain numbers 1-9");
+ }
+ }
- int[][] expected = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+ int[][] expectedSolution = {
+ {5, 3, 4, 6, 7, 8, 9, 1, 2},
+ {6, 7, 2, 1, 9, 5, 3, 4, 8},
+ {1, 9, 8, 3, 4, 2, 5, 6, 7},
+ {8, 5, 9, 7, 6, 1, 4, 2, 3},
+ {4, 2, 6, 8, 5, 3, 7, 9, 1},
+ {7, 1, 3, 9, 2, 4, 8, 5, 6},
+ {9, 6, 1, 5, 3, 7, 2, 8, 4},
+ {2, 8, 7, 4, 1, 9, 6, 3, 5},
+ {3, 4, 5, 2, 8, 6, 1, 7, 9}
+ };
- assertArrayEquals(expected, board);
+ assertArrayEquals(expectedSolution, board, "The solved board should match the expected solution");
}
@Test
- void testSolveSudokuHardPuzzle() {
- int[][] board = {{0, 0, 0, 0, 0, 0, 6, 8, 0}, {0, 0, 0, 0, 7, 3, 0, 0, 9}, {3, 0, 9, 0, 0, 0, 0, 4, 5}, {4, 9, 0, 0, 0, 0, 0, 0, 0}, {8, 0, 3, 0, 5, 0, 9, 0, 2}, {0, 0, 0, 0, 0, 0, 0, 3, 6}, {9, 6, 0, 0, 0, 0, 3, 0, 8}, {7, 0, 0, 6, 8, 0, 0, 0, 0}, {0, 2, 8, 0, 0, 0, 0, 0, 0}};
+ void testUnsolvableSudoku() {
+ int[][] board = {
+ {5, 5, 0, 0, 7, 0, 0, 0, 0},
+ {6, 0, 0, 1, 9, 5, 0, 0, 0},
+ {0, 9, 8, 0, 0, 0, 0, 6, 0},
+ {8, 0, 0, 0, 6, 0, 0, 0, 3},
+ {4, 0, 0, 8, 0, 3, 0, 0, 1},
+ {7, 0, 0, 0, 2, 0, 0, 0, 6},
+ {0, 6, 0, 0, 0, 0, 2, 8, 0},
+ {0, 0, 0, 4, 1, 9, 0, 0, 5},
+ {0, 0, 0, 0, 8, 0, 0, 7, 9}
+ };
- assertTrue(SudokuSolver.solveSudoku(board));
+ assertFalse(SudokuSolver.solveSudoku(board), "Invalid Sudoku puzzle should be unsolvable");
}
@Test
- void testSolveSudokuAlreadySolved() {
- int[][] board = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+ void testAlreadySolvedSudoku() {
+ int[][] board = {
+ {5, 3, 4, 6, 7, 8, 9, 1, 2},
+ {6, 7, 2, 1, 9, 5, 3, 4, 8},
+ {1, 9, 8, 3, 4, 2, 5, 6, 7},
+ {8, 5, 9, 7, 6, 1, 4, 2, 3},
+ {4, 2, 6, 8, 5, 3, 7, 9, 1},
+ {7, 1, 3, 9, 2, 4, 8, 5, 6},
+ {9, 6, 1, 5, 3, 7, 2, 8, 4},
+ {2, 8, 7, 4, 1, 9, 6, 3, 5},
+ {3, 4, 5, 2, 8, 6, 1, 7, 9}
+ };
- assertTrue(SudokuSolver.solveSudoku(board));
+ assertTrue(SudokuSolver.solveSudoku(board), "Already solved Sudoku should return true");
+
+ int[][] expected = {
+ {5, 3, 4, 6, 7, 8, 9, 1, 2},
+ {6, 7, 2, 1, 9, 5, 3, 4, 8},
+ {1, 9, 8, 3, 4, 2, 5, 6, 7},
+ {8, 5, 9, 7, 6, 1, 4, 2, 3},
+ {4, 2, 6, 8, 5, 3, 7, 9, 1},
+ {7, 1, 3, 9, 2, 4, 8, 5, 6},
+ {9, 6, 1, 5, 3, 7, 2, 8, 4},
+ {2, 8, 7, 4, 1, 9, 6, 3, 5},
+ {3, 4, 5, 2, 8, 6, 1, 7, 9}
+ };
+
+ assertArrayEquals(expected, board, "Already solved board should remain unchanged");
}
@Test
- void testSolveSudokuInvalidSize() {
- int[][] board = {{1, 2, 3}, {4, 5, 6}};
- assertFalse(SudokuSolver.solveSudoku(board));
- }
+ void testEmptySudoku() {
+ int[][] board = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0}
+ };
- @Test
- void testSolveSudokuNullBoard() {
- assertFalse(SudokuSolver.solveSudoku(null));
+ assertTrue(SudokuSolver.solveSudoku(board), "Empty Sudoku should be solvable");
+
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ assertTrue(board[i][j] >= 1 && board[i][j] <= 9, "All cells should be filled with 1-9");
+ }
+ }
}
@Test
- void testSolveSudokuEmptyBoard() {
- int[][] board = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}};
+ void testDifficultSudoku() {
+ int[][] board = {
+ {0, 0, 0, 0, 0, 0, 6, 8, 0},
+ {0, 0, 0, 0, 7, 3, 0, 0, 9},
+ {3, 0, 9, 0, 0, 0, 0, 4, 5},
+ {4, 9, 0, 0, 0, 0, 0, 0, 0},
+ {8, 0, 3, 0, 5, 0, 9, 0, 2},
+ {0, 0, 0, 0, 0, 0, 0, 3, 6},
+ {9, 6, 0, 0, 0, 0, 3, 0, 8},
+ {7, 0, 0, 6, 8, 0, 0, 0, 0},
+ {0, 2, 8, 0, 0, 0, 0, 0, 0}
+ };
- assertTrue(SudokuSolver.solveSudoku(board));
+ assertTrue(SudokuSolver.solveSudoku(board), "Difficult Sudoku puzzle should be solvable");
+
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ assertTrue(board[i][j] >= 1 && board[i][j] <= 9, "All cells should contain numbers 1-9");
+ }
+ }
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFSTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFSTest.java
new file mode 100644
index 000000000000..8b4aeb581d85
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFSTest.java
@@ -0,0 +1,264 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for TopologicalSortDFS
+ *
+ * @author Raghu0703
+ */
+class TopologicalSortDFSTest {
+
+ /**
+ * Helper method to create a graph with given number of vertices
+ */
+ 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 a directed edge to the graph
+ */
+ private void addEdge(List> graph, int from, int to) {
+ graph.get(from).add(to);
+ }
+
+ @Test
+ void testSimpleDAG() {
+ // Graph: 0 → 1 → 2
+ // ↓
+ // 3
+ List> graph = createGraph(4);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 0, 3);
+ addEdge(graph, 1, 2);
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ // Valid topological orders: [0, 1, 3, 2] or [0, 3, 1, 2]
+ assertEquals(4, result.size());
+ assertTrue(result.indexOf(0) < result.indexOf(1));
+ assertTrue(result.indexOf(0) < result.indexOf(3));
+ assertTrue(result.indexOf(1) < result.indexOf(2));
+ }
+
+ @Test
+ void testComplexDAG() {
+ // Graph representing course dependencies
+ // 5 → 2 → 3 → 1
+ // ↓ ↑
+ // 0 → 4 →
+ List> graph = createGraph(6);
+ addEdge(graph, 5, 2);
+ addEdge(graph, 5, 0);
+ addEdge(graph, 4, 0);
+ addEdge(graph, 4, 1);
+ addEdge(graph, 2, 3);
+ addEdge(graph, 3, 1);
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ // Verify dependencies are maintained
+ assertEquals(6, result.size());
+ assertTrue(result.indexOf(5) < result.indexOf(2));
+ assertTrue(result.indexOf(5) < result.indexOf(0));
+ assertTrue(result.indexOf(4) < result.indexOf(1));
+ assertTrue(result.indexOf(2) < result.indexOf(3));
+ assertTrue(result.indexOf(3) < result.indexOf(1));
+ }
+
+ @Test
+ void testLinearDAG() {
+ // Graph: 0 → 1 → 2 → 3 → 4
+ List> graph = createGraph(5);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 3);
+ addEdge(graph, 3, 4);
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ assertEquals(Arrays.asList(0, 1, 2, 3, 4), result);
+ }
+
+ @Test
+ void testDisconnectedDAG() {
+ // Graph with disconnected components:
+ // 0 → 1 2 → 3
+ List> graph = createGraph(4);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 2, 3);
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ assertEquals(4, result.size());
+ assertTrue(result.indexOf(0) < result.indexOf(1));
+ assertTrue(result.indexOf(2) < result.indexOf(3));
+ }
+
+ @Test
+ void testSingleVertex() {
+ // Graph with single vertex and no edges
+ List> graph = createGraph(1);
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ assertEquals(Arrays.asList(0), result);
+ }
+
+ @Test
+ void testEmptyGraph() {
+ // Empty graph
+ List> graph = new ArrayList<>();
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ void testGraphWithSelfLoop() {
+ // Graph with self loop: 0 → 0
+ List> graph = createGraph(1);
+ addEdge(graph, 0, 0);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ TopologicalSortDFS.topologicalSort(graph);
+ });
+ }
+
+ @Test
+ void testSimpleCycle() {
+ // Graph with cycle: 0 → 1 → 2 → 0
+ List> graph = createGraph(3);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 0);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ TopologicalSortDFS.topologicalSort(graph);
+ });
+ }
+
+ @Test
+ void testComplexCycle() {
+ // Graph with cycle: 0 → 1 → 2
+ // ↑ ↓
+ // 4 ← 3 ←
+ List> graph = createGraph(5);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 3);
+ addEdge(graph, 3, 4);
+ addEdge(graph, 4, 0);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ TopologicalSortDFS.topologicalSort(graph);
+ });
+ }
+
+ @Test
+ void testIsDAGWithValidGraph() {
+ // Valid DAG: 0 → 1 → 2
+ List> graph = createGraph(3);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+
+ assertTrue(TopologicalSortDFS.isDAG(graph));
+ }
+
+ @Test
+ void testIsDAGWithCycle() {
+ // Graph with cycle: 0 → 1 → 2 → 0
+ List> graph = createGraph(3);
+ addEdge(graph, 0, 1);
+ addEdge(graph, 1, 2);
+ addEdge(graph, 2, 0);
+
+ assertFalse(TopologicalSortDFS.isDAG(graph));
+ }
+
+ @Test
+ void testIsDAGWithEmptyGraph() {
+ List> graph = new ArrayList<>();
+ assertTrue(TopologicalSortDFS.isDAG(graph));
+ }
+
+ @Test
+ void testIsDAGWithSelfLoop() {
+ List> graph = createGraph(1);
+ addEdge(graph, 0, 0);
+
+ assertFalse(TopologicalSortDFS.isDAG(graph));
+ }
+
+ @Test
+ void testNullGraph() {
+ List result = TopologicalSortDFS.topologicalSort(null);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ void testTaskSchedulingScenario() {
+ // Real-world scenario: Build system dependencies
+ // Task 0: Download dependencies
+ // Task 1: Compile source
+ // Task 2: Run tests
+ // Task 3: Package
+ // Task 4: Deploy
+ // Dependencies: 0 → 1 → 2 → 3 → 4
+ // 0 → 2 (tests need dependencies)
+ List> graph = createGraph(5);
+ addEdge(graph, 0, 1); // Download before compile
+ addEdge(graph, 1, 2); // Compile before test
+ addEdge(graph, 2, 3); // Test before package
+ addEdge(graph, 3, 4); // Package before deploy
+ addEdge(graph, 0, 2); // Download before test
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ // Verify all dependencies are respected
+ assertTrue(result.indexOf(0) < result.indexOf(1));
+ assertTrue(result.indexOf(1) < result.indexOf(2));
+ assertTrue(result.indexOf(2) < result.indexOf(3));
+ assertTrue(result.indexOf(3) < result.indexOf(4));
+ assertTrue(result.indexOf(0) < result.indexOf(2));
+ }
+
+ @Test
+ void testCoursePrerequisiteScenario() {
+ // Course prerequisites scenario
+ // Course 0: Intro to CS
+ // Course 1: Data Structures
+ // Course 2: Algorithms
+ // Course 3: Advanced Algorithms
+ // Course 4: Machine Learning
+ List> graph = createGraph(5);
+ addEdge(graph, 0, 1); // Intro → Data Structures
+ addEdge(graph, 1, 2); // Data Structures → Algorithms
+ addEdge(graph, 2, 3); // Algorithms → Advanced Algorithms
+ addEdge(graph, 2, 4); // Algorithms → Machine Learning
+ addEdge(graph, 1, 4); // Data Structures → Machine Learning
+
+ List result = TopologicalSortDFS.topologicalSort(graph);
+
+ // Verify course prerequisites
+ assertTrue(result.indexOf(0) < result.indexOf(1));
+ assertTrue(result.indexOf(1) < result.indexOf(2));
+ assertTrue(result.indexOf(2) < result.indexOf(3));
+ assertTrue(result.indexOf(2) < result.indexOf(4));
+ assertTrue(result.indexOf(1) < result.indexOf(4));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/nano b/src/test/java/com/thealgorithms/datastructures/graphs/nano
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/src/test/java/com/thealgorithms/graphs/KruskalTest.java b/src/test/java/com/thealgorithms/graphs/KruskalTest.java
new file mode 100644
index 000000000000..059ee50b2428
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graphs/KruskalTest.java
@@ -0,0 +1,156 @@
+package com.thealgorithms.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.graphs.Kruskal.Edge;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for Kruskal's Algorithm
+ *
+ * @author Raghu0703
+ */
+class KruskalTest {
+
+ @Test
+ void testSimpleGraph() {
+ // Graph with 4 vertices
+ int vertices = 4;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 10));
+ edges.add(new Edge(0, 2, 6));
+ edges.add(new Edge(0, 3, 5));
+ edges.add(new Edge(1, 3, 15));
+ edges.add(new Edge(2, 3, 4));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ // MST should have exactly 3 edges (V-1)
+ assertEquals(3, mst.size());
+
+ // Total weight should be 19 (4 + 5 + 10)
+ assertEquals(19, Kruskal.getMSTWeight(mst));
+ }
+
+ @Test
+ void testDisconnectedComponents() {
+ // Graph with 5 vertices but only 3 can be connected
+ int vertices = 5;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 1));
+ edges.add(new Edge(1, 2, 2));
+ edges.add(new Edge(3, 4, 3));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ // MST should have 3 edges (not complete spanning tree due to disconnection)
+ assertEquals(3, mst.size());
+ assertEquals(6, Kruskal.getMSTWeight(mst));
+ }
+
+ @Test
+ void testSingleEdge() {
+ int vertices = 2;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 5));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ assertEquals(1, mst.size());
+ assertEquals(5, Kruskal.getMSTWeight(mst));
+ }
+
+ @Test
+ void testCompleteGraph() {
+ // Complete graph with 4 vertices
+ int vertices = 4;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 1));
+ edges.add(new Edge(0, 2, 4));
+ edges.add(new Edge(0, 3, 3));
+ edges.add(new Edge(1, 2, 2));
+ edges.add(new Edge(1, 3, 5));
+ edges.add(new Edge(2, 3, 6));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ // MST should have 3 edges
+ assertEquals(3, mst.size());
+
+ // Total weight should be 6 (1 + 2 + 3)
+ assertEquals(6, Kruskal.getMSTWeight(mst));
+ }
+
+ @Test
+ void testGraphWithEqualWeights() {
+ int vertices = 3;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 5));
+ edges.add(new Edge(1, 2, 5));
+ edges.add(new Edge(0, 2, 5));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ assertEquals(2, mst.size());
+ assertEquals(10, Kruskal.getMSTWeight(mst));
+ }
+
+ @Test
+ void testEmptyGraph() {
+ int vertices = 3;
+ List edges = new ArrayList<>();
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ assertTrue(mst.isEmpty());
+ }
+
+ @Test
+ void testInvalidVertexCount() {
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 10));
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ Kruskal.kruskalMST(0, edges);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ Kruskal.kruskalMST(-5, edges);
+ });
+ }
+
+ @Test
+ void testNullEdges() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ Kruskal.kruskalMST(5, null);
+ });
+ }
+
+ @Test
+ void testLargerGraph() {
+ // Graph with 6 vertices
+ int vertices = 6;
+ List edges = new ArrayList<>();
+ edges.add(new Edge(0, 1, 4));
+ edges.add(new Edge(0, 2, 4));
+ edges.add(new Edge(1, 2, 2));
+ edges.add(new Edge(1, 3, 5));
+ edges.add(new Edge(2, 3, 8));
+ edges.add(new Edge(2, 4, 10));
+ edges.add(new Edge(3, 4, 2));
+ edges.add(new Edge(3, 5, 6));
+ edges.add(new Edge(4, 5, 3));
+
+ List mst = Kruskal.kruskalMST(vertices, edges);
+
+ // MST should have 5 edges (6-1)
+ assertEquals(5, mst.size());
+
+ // Verify minimum total weight
+ assertEquals(16, Kruskal.getMSTWeight(mst));
+ }
+}