From 6ecbd4132a2b9fb87213dfe27ab8d344407fd0b2 Mon Sep 17 00:00:00 2001 From: Siddhram Date: Thu, 9 Oct 2025 22:54:04 +0530 Subject: [PATCH 1/5] feat(graph): Add TopologicalSort and DisjointSet implementations --- DIRECTORY.md | 2 + .../com/thealgorithms/graph/DisjointSet.java | 185 ++++++++++++++++++ .../thealgorithms/graph/TopologicalSort.java | 123 ++++++++++++ .../thealgorithms/graph/DisjointSetTest.java | 121 ++++++++++++ .../graph/TopologicalSortTest.java | 90 +++++++++ 5 files changed, 521 insertions(+) create mode 100644 src/main/java/com/thealgorithms/graph/DisjointSet.java create mode 100644 src/main/java/com/thealgorithms/graph/TopologicalSort.java create mode 100644 src/test/java/com/thealgorithms/graph/DisjointSetTest.java create mode 100644 src/test/java/com/thealgorithms/graph/TopologicalSortTest.java diff --git a/DIRECTORY.md b/DIRECTORY.md index b311b10fa177..c6b20517eb34 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -348,9 +348,11 @@ - 📄 [Point](src/main/java/com/thealgorithms/geometry/Point.java) - 📁 **graph** - 📄 [ConstrainedShortestPath](src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java) + - 📄 [DisjointSet](src/main/java/com/thealgorithms/graph/DisjointSet.java) - 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java) - 📄 [PredecessorConstrainedDfs](src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java) - 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) + - 📄 [TopologicalSort](src/main/java/com/thealgorithms/graph/TopologicalSort.java) - 📄 [TravelingSalesman](src/main/java/com/thealgorithms/graph/TravelingSalesman.java) - 📁 **greedyalgorithms** - 📄 [ActivitySelection](src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java new file mode 100644 index 000000000000..384b75967d80 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -0,0 +1,185 @@ +package com.thealgorithms.graph; + +import java.util.*; + +/** + * Implementation of the Disjoint Set (Union-Find) data structure with path + * compression + * and union by rank optimizations. + * + *

+ * A disjoint-set data structure maintains a collection of disjoint dynamic + * sets. + * Each set is represented by a "representative" element. The data structure + * supports + * two main operations: + *

+ * + * + *

+ * Time Complexity: + *

+ * + *

+ * where α(n) is the inverse Ackermann function, which grows extremely slowly. + * For all practical values of n, α(n) ≤ 4. + *

+ * + *

+ * Space Complexity: O(n) where n is the number of elements + *

+ * + *

+ * Applications: + *

+ * + */ +public class DisjointSet { + private final int[] parent; + private final int[] rank; + private final int size; + private int numSets; // Tracks number of disjoint sets + + /** + * Initializes a disjoint set data structure with elements from 0 to size-1. + * + * @param size number of elements + * @throws IllegalArgumentException if size is negative + */ + public DisjointSet(int size) { + if (size < 0) { + throw new IllegalArgumentException("Size must be non-negative"); + } + this.size = size; + this.numSets = size; + parent = new int[size]; + rank = new int[size]; + + // Initialize each element as its own set + for (int i = 0; i < size; i++) { + parent[i] = i; + rank[i] = 0; + } + } + + /** + * Finds the representative of the set containing element x. + * Uses path compression to optimize future queries. + * + * @param x element to find representative for + * @return representative of x's set + * @throws IllegalArgumentException if x is out of bounds + */ + public int find(int x) { + if (x < 0 || x >= size) { + throw new IllegalArgumentException("Element out of bounds: " + x); + } + + // Path compression: Make all nodes on path point directly to root + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + /** + * Merges the sets containing elements x and y. + * Uses union by rank to keep the tree shallow. + * + * @param x first element + * @param y second element + * @return true if x and y were in different sets, false if they were already in + * same set + * @throws IllegalArgumentException if either element is out of bounds + */ + public boolean union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + + if (rootX == rootY) { + return false; // Already in same set + } + + // Union by rank: Attach smaller rank tree under root of higher rank tree + if (rank[rootX] < rank[rootY]) { + parent[rootX] = rootY; + } else if (rank[rootX] > rank[rootY]) { + parent[rootY] = rootX; + } else { + parent[rootY] = rootX; + rank[rootX]++; + } + + numSets--; + return true; + } + + /** + * Checks if two elements are in the same set. + * + * @param x first element + * @param y second element + * @return true if x and y are in the same set + * @throws IllegalArgumentException if either element is out of bounds + */ + public boolean connected(int x, int y) { + return find(x) == find(y); + } + + /** + * Returns the current number of disjoint sets. + * + * @return number of disjoint sets + */ + public int getNumSets() { + return numSets; + } + + /** + * Returns the size of the set containing element x. + * + * @param x element to find set size for + * @return size of x's set + * @throws IllegalArgumentException if x is out of bounds + */ + public int getSetSize(int x) { + int root = find(x); + int count = 0; + for (int i = 0; i < size; i++) { + if (find(i) == root) { + count++; + } + } + return count; + } + + /** + * Returns all elements in the same set as x. + * + * @param x element to find set members for + * @return list of all elements in x's set + * @throws IllegalArgumentException if x is out of bounds + */ + public List getSetMembers(int x) { + int root = find(x); + List members = new ArrayList<>(); + for (int i = 0; i < size; i++) { + if (find(i) == root) { + members.add(i); + } + } + return members; + } +} \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/graph/TopologicalSort.java b/src/main/java/com/thealgorithms/graph/TopologicalSort.java new file mode 100644 index 000000000000..2c5c10b31819 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/TopologicalSort.java @@ -0,0 +1,123 @@ +package com.thealgorithms.graph; + +import java.util.*; + +/** + * Implementation of Kahn's algorithm for topological sorting of a directed + * acyclic graph (DAG). + * + *

+ * The algorithm finds a linear ordering of vertices such that for every + * directed edge u -> v, + * vertex u comes before v in the ordering. A topological ordering is possible + * if and only if the + * graph has no directed cycles (i.e., it is a DAG). + *

+ * + *

+ * 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 queue and in-degree array + *

+ * + *

+ * Applications: + *

+ *
    + *
  • Task scheduling with dependencies
  • + *
  • Build system dependency resolution
  • + *
  • Course prerequisite planning
  • + *
  • Package dependency management
  • + *
+ */ +public final class TopologicalSort { + + private TopologicalSort() { + } + + /** + * Performs topological sorting using Kahn's algorithm. + * + * @param numVertices number of vertices in the graph (0 to numVertices-1) + * @param edges list of directed edges, where each edge is represented as + * int[]{from, to} + * @return an array containing the topologically sorted order, or null if a + * cycle exists + * @throws IllegalArgumentException if edges is null or contains invalid + * vertices + */ + public static int[] sort(int numVertices, List edges) { + if (edges == null) { + throw new IllegalArgumentException("Edge list must not be null"); + } + + // Create adjacency list representation + List> graph = new ArrayList<>(numVertices); + for (int i = 0; i < numVertices; i++) { + graph.add(new ArrayList<>()); + } + + // Calculate in-degree for each vertex + int[] inDegree = new int[numVertices]; + for (int[] edge : edges) { + if (edge[0] < 0 || edge[0] >= numVertices || edge[1] < 0 || edge[1] >= numVertices) { + throw new IllegalArgumentException("Invalid vertex in edge: " + Arrays.toString(edge)); + } + graph.get(edge[0]).add(edge[1]); + inDegree[edge[1]]++; + } + + // Initialize queue with vertices having no incoming edges + Queue queue = new LinkedList<>(); + for (int i = 0; i < numVertices; i++) { + if (inDegree[i] == 0) { + queue.offer(i); + } + } + + int[] result = new int[numVertices]; + int index = 0; + + // Process vertices in topological order + while (!queue.isEmpty()) { + int vertex = queue.poll(); + result[index++] = vertex; + + // Reduce in-degree of neighbors and add to queue if in-degree becomes 0 + for (int neighbor : graph.get(vertex)) { + inDegree[neighbor]--; + if (inDegree[neighbor] == 0) { + queue.offer(neighbor); + } + } + } + + // Check if topological sort is possible (no cycles) + return index == numVertices ? result : null; + } + + /** + * Alternative version that returns the result as a List and throws an exception + * if a cycle is detected. + * + * @param numVertices number of vertices in the graph (0 to numVertices-1) + * @param edges list of directed edges, where each edge is represented as + * int[]{from, to} + * @return a list containing the vertices in topologically sorted order + * @throws IllegalArgumentException if the graph contains a cycle or if input is + * invalid + */ + public static List sortAndDetectCycle(int numVertices, List edges) { + int[] result = sort(numVertices, edges); + if (result == null) { + throw new IllegalArgumentException("Graph contains a cycle"); + } + List sorted = new ArrayList<>(numVertices); + for (int vertex : result) { + sorted.add(vertex); + } + return sorted; + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java new file mode 100644 index 000000000000..50780e252241 --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java @@ -0,0 +1,121 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DisjointSetTest { + + @Test + @DisplayName("Initially all elements are in separate sets") + void initialState() { + DisjointSet ds = new DisjointSet(5); + assertEquals(5, ds.getNumSets()); + for (int i = 0; i < 5; i++) { + assertEquals(i, ds.find(i)); + assertEquals(1, ds.getSetSize(i)); + } + } + + @Test + @DisplayName("Union of elements creates correct sets") + void basicUnion() { + DisjointSet ds = new DisjointSet(4); + assertTrue(ds.union(0, 1)); // Should succeed + assertTrue(ds.union(2, 3)); // Should succeed + assertFalse(ds.union(0, 1)); // Should fail (already united) + assertEquals(2, ds.getNumSets()); + assertTrue(ds.connected(0, 1)); + assertTrue(ds.connected(2, 3)); + assertFalse(ds.connected(0, 2)); + } + + @Test + @DisplayName("Path compression optimizes tree structure") + void pathCompression() { + DisjointSet ds = new DisjointSet(4); + ds.union(0, 1); + ds.union(1, 2); + ds.union(2, 3); + // After these unions, we should have one set + assertEquals(1, ds.getNumSets()); + // After path compression, all elements should point to the same root + int root = ds.find(0); + for (int i = 1; i < 4; i++) { + assertEquals(root, ds.find(i)); + } + } + + @Test + @DisplayName("Set size tracking works correctly") + void setSizeTracking() { + DisjointSet ds = new DisjointSet(6); + ds.union(0, 1); // Set of size 2 + ds.union(2, 3); // Another set of size 2 + ds.union(0, 2); // Merge into set of size 4 + assertEquals(4, ds.getSetSize(0)); + assertEquals(4, ds.getSetSize(1)); + assertEquals(4, ds.getSetSize(2)); + assertEquals(4, ds.getSetSize(3)); + assertEquals(1, ds.getSetSize(4)); + assertEquals(1, ds.getSetSize(5)); + } + + @Test + @DisplayName("Get set members returns correct lists") + void getSetMembers() { + DisjointSet ds = new DisjointSet(4); + ds.union(0, 1); + ds.union(2, 3); + + List set1 = ds.getSetMembers(0); + List set2 = ds.getSetMembers(2); + + assertEquals(2, set1.size()); + assertTrue(set1.contains(0)); + assertTrue(set1.contains(1)); + + assertEquals(2, set2.size()); + assertTrue(set2.contains(2)); + assertTrue(set2.contains(3)); + } + + @Test + @DisplayName("Out of bounds access throws exception") + void outOfBounds() { + DisjointSet ds = new DisjointSet(3); + assertThrows(IllegalArgumentException.class, () -> ds.find(-1)); + assertThrows(IllegalArgumentException.class, () -> ds.find(3)); + assertThrows(IllegalArgumentException.class, () -> ds.union(-1, 0)); + assertThrows(IllegalArgumentException.class, () -> ds.union(0, 3)); + } + + @Test + @DisplayName("Negative size throws exception") + void negativeSize() { + assertThrows(IllegalArgumentException.class, () -> new DisjointSet(-1)); + } + + @Test + @DisplayName("Connected components example") + void connectedComponents() { + DisjointSet ds = new DisjointSet(6); + // Create two connected components: 0-1-2 and 3-4-5 + ds.union(0, 1); + ds.union(1, 2); + ds.union(3, 4); + ds.union(4, 5); + + assertEquals(2, ds.getNumSets()); + + // Check connectivity within components + assertTrue(ds.connected(0, 2)); + assertTrue(ds.connected(3, 5)); + + // Check separation between components + assertFalse(ds.connected(0, 3)); + assertFalse(ds.connected(2, 4)); + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java new file mode 100644 index 000000000000..d34c22ed15cc --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java @@ -0,0 +1,90 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TopologicalSortTest { + + @Test + @DisplayName("Simple DAG returns correct ordering") + void simpleDAG() { + List edges = Arrays.asList( + new int[] { 0, 1 }, + new int[] { 0, 2 }, + new int[] { 1, 3 }, + new int[] { 2, 3 }); + int[] result = TopologicalSort.sort(4, edges); + assertArrayEquals(new int[] { 0, 1, 2, 3 }, result); + } + + @Test + @DisplayName("Empty graph returns valid ordering") + void emptyGraph() { + List edges = Arrays.asList(); + int[] result = TopologicalSort.sort(3, edges); + assertEquals(3, result.length); + // Any permutation is valid for empty graph + assertTrue(Arrays.stream(result).allMatch(v -> v >= 0 && v < 3)); + } + + @Test + @DisplayName("Graph with cycle returns null") + void graphWithCycle() { + List edges = Arrays.asList( + new int[] { 0, 1 }, + new int[] { 1, 2 }, + new int[] { 2, 0 }); + assertNull(TopologicalSort.sort(3, edges)); + } + + @Test + @DisplayName("Course prerequisites example") + void coursePrerequisites() { + // Example: Course prerequisites where edge [a,b] means course a must be taken + // before b + List edges = Arrays.asList( + new int[] { 1, 0 }, // Calculus I -> Calculus II + new int[] { 2, 0 }, // Linear Algebra -> Calculus II + new int[] { 1, 3 }, // Calculus I -> Differential Equations + new int[] { 2, 3 } // Linear Algebra -> Differential Equations + ); + List result = TopologicalSort.sortAndDetectCycle(4, edges); + // Either [1,2,0,3] or [2,1,0,3] is valid + assertEquals(4, result.size()); + // Verify prerequisites are satisfied + assertTrue(result.indexOf(1) < result.indexOf(0)); // Calc I before Calc II + assertTrue(result.indexOf(2) < result.indexOf(0)); // Linear Algebra before Calc II + assertTrue(result.indexOf(1) < result.indexOf(3)); // Calc I before Diff Eq + assertTrue(result.indexOf(2) < result.indexOf(3)); // Linear Algebra before Diff Eq + } + + @Test + @DisplayName("Invalid vertex throws exception") + void invalidVertex() { + List edges = Arrays.asList( + new int[] { 0, 5 } // Vertex 5 is invalid for a graph with 3 vertices + ); + assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sort(3, edges)); + } + + @Test + @DisplayName("Null edge list throws exception") + void nullEdgeList() { + assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sort(3, null)); + } + + @Test + @DisplayName("sortAndDetectCycle throws exception for cyclic graph") + void detectCycleThrowsException() { + List edges = Arrays.asList( + new int[] { 0, 1 }, + new int[] { 1, 2 }, + new int[] { 2, 0 }); + assertThrows(IllegalArgumentException.class, + () -> TopologicalSort.sortAndDetectCycle(3, edges)); + } +} \ No newline at end of file From f6c204d83bf5f64cd3b902b4d408f85ea56b186d Mon Sep 17 00:00:00 2001 From: Siddhram Date: Thu, 9 Oct 2025 23:04:22 +0530 Subject: [PATCH 2/5] style: Apply Java code style guidelines --- src/main/java/com/thealgorithms/graph/DisjointSet.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index 384b75967d80..6c945d1edb8f 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -59,15 +59,13 @@ public class DisjointSet { * @throws IllegalArgumentException if size is negative */ public DisjointSet(int size) { - if (size < 0) { + if (size < 0) throw new IllegalArgumentException("Size must be non-negative"); - } this.size = size; this.numSets = size; parent = new int[size]; rank = new int[size]; - // Initialize each element as its own set for (int i = 0; i < size; i++) { parent[i] = i; rank[i] = 0; From 60105669e5a6b05244a27641c813f2c524a5ce21 Mon Sep 17 00:00:00 2001 From: Siddhram Date: Thu, 9 Oct 2025 23:15:54 +0530 Subject: [PATCH 3/5] style: Apply Java code style guidelines --- src/main/java/com/thealgorithms/graph/DisjointSet.java | 3 ++- src/main/java/com/thealgorithms/graph/TopologicalSort.java | 6 +++++- src/test/java/com/thealgorithms/graph/DisjointSetTest.java | 5 ++++- .../java/com/thealgorithms/graph/TopologicalSortTest.java | 6 +++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index 6c945d1edb8f..aaf78507ed90 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -1,6 +1,7 @@ package com.thealgorithms.graph; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * Implementation of the Disjoint Set (Union-Find) data structure with path diff --git a/src/main/java/com/thealgorithms/graph/TopologicalSort.java b/src/main/java/com/thealgorithms/graph/TopologicalSort.java index 2c5c10b31819..36a3bb5236e8 100644 --- a/src/main/java/com/thealgorithms/graph/TopologicalSort.java +++ b/src/main/java/com/thealgorithms/graph/TopologicalSort.java @@ -1,6 +1,10 @@ package com.thealgorithms.graph; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; /** * Implementation of Kahn's algorithm for topological sorting of a directed diff --git a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java index 50780e252241..b74cbd196f84 100644 --- a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java +++ b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java @@ -1,6 +1,9 @@ package com.thealgorithms.graph; -import static org.junit.jupiter.api.Assertions.*; +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.List; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java index d34c22ed15cc..733a82c4b90c 100644 --- a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java +++ b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java @@ -1,6 +1,10 @@ package com.thealgorithms.graph; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.List; From ef0c8eb60b91e297af13c01d1fa0a2802c0f1f6d Mon Sep 17 00:00:00 2001 From: Siddhram Date: Thu, 9 Oct 2025 23:47:46 +0530 Subject: [PATCH 4/5] style: Apply Java code style guidelines --- .../com/thealgorithms/graph/DisjointSet.java | 5 ++-- .../thealgorithms/graph/TopologicalSort.java | 2 +- .../thealgorithms/graph/DisjointSetTest.java | 2 +- .../graph/TopologicalSortTest.java | 26 +++++-------------- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index aaf78507ed90..d1ad400007ef 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -60,8 +60,9 @@ public class DisjointSet { * @throws IllegalArgumentException if size is negative */ public DisjointSet(int size) { - if (size < 0) + if (size < 0) { throw new IllegalArgumentException("Size must be non-negative"); + } this.size = size; this.numSets = size; parent = new int[size]; @@ -181,4 +182,4 @@ public List getSetMembers(int x) { } return members; } -} \ No newline at end of file +} diff --git a/src/main/java/com/thealgorithms/graph/TopologicalSort.java b/src/main/java/com/thealgorithms/graph/TopologicalSort.java index 36a3bb5236e8..853eb13b8695 100644 --- a/src/main/java/com/thealgorithms/graph/TopologicalSort.java +++ b/src/main/java/com/thealgorithms/graph/TopologicalSort.java @@ -124,4 +124,4 @@ public static List sortAndDetectCycle(int numVertices, List edge } return sorted; } -} \ No newline at end of file +} diff --git a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java index b74cbd196f84..58dc09fc23b5 100644 --- a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java +++ b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java @@ -121,4 +121,4 @@ void connectedComponents() { assertFalse(ds.connected(0, 3)); assertFalse(ds.connected(2, 4)); } -} \ No newline at end of file +} diff --git a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java index 733a82c4b90c..6ef853ec48f0 100644 --- a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java +++ b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java @@ -16,10 +16,7 @@ class TopologicalSortTest { @Test @DisplayName("Simple DAG returns correct ordering") void simpleDAG() { - List edges = Arrays.asList( - new int[] { 0, 1 }, - new int[] { 0, 2 }, - new int[] { 1, 3 }, + List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 0, 2 }, new int[] { 1, 3 }, new int[] { 2, 3 }); int[] result = TopologicalSort.sort(4, edges); assertArrayEquals(new int[] { 0, 1, 2, 3 }, result); @@ -38,10 +35,7 @@ void emptyGraph() { @Test @DisplayName("Graph with cycle returns null") void graphWithCycle() { - List edges = Arrays.asList( - new int[] { 0, 1 }, - new int[] { 1, 2 }, - new int[] { 2, 0 }); + List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 1, 2 }, new int[] { 2, 0 }); assertNull(TopologicalSort.sort(3, edges)); } @@ -50,8 +44,7 @@ void graphWithCycle() { void coursePrerequisites() { // Example: Course prerequisites where edge [a,b] means course a must be taken // before b - List edges = Arrays.asList( - new int[] { 1, 0 }, // Calculus I -> Calculus II + List edges = Arrays.asList(new int[] { 1, 0 }, // Calculus I -> Calculus II new int[] { 2, 0 }, // Linear Algebra -> Calculus II new int[] { 1, 3 }, // Calculus I -> Differential Equations new int[] { 2, 3 } // Linear Algebra -> Differential Equations @@ -69,8 +62,7 @@ void coursePrerequisites() { @Test @DisplayName("Invalid vertex throws exception") void invalidVertex() { - List edges = Arrays.asList( - new int[] { 0, 5 } // Vertex 5 is invalid for a graph with 3 vertices + List edges = Arrays.asList(new int[] { 0, 5 } // Vertex 5 is invalid for a graph with 3 vertices ); assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sort(3, edges)); } @@ -84,11 +76,7 @@ void nullEdgeList() { @Test @DisplayName("sortAndDetectCycle throws exception for cyclic graph") void detectCycleThrowsException() { - List edges = Arrays.asList( - new int[] { 0, 1 }, - new int[] { 1, 2 }, - new int[] { 2, 0 }); - assertThrows(IllegalArgumentException.class, - () -> TopologicalSort.sortAndDetectCycle(3, edges)); + List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 1, 2 }, new int[] { 2, 0 }); + assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sortAndDetectCycle(3, edges)); } -} \ No newline at end of file +} From d4e9179656ba340c53a804f0049d6f9ca9daa1d2 Mon Sep 17 00:00:00 2001 From: Siddhram Date: Thu, 9 Oct 2025 23:54:14 +0530 Subject: [PATCH 5/5] style: Apply Java code style guidelines --- .../thealgorithms/graph/TopologicalSort.java | 2 +- .../graph/TopologicalSortTest.java | 34 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/TopologicalSort.java b/src/main/java/com/thealgorithms/graph/TopologicalSort.java index 853eb13b8695..b6e84c67f051 100644 --- a/src/main/java/com/thealgorithms/graph/TopologicalSort.java +++ b/src/main/java/com/thealgorithms/graph/TopologicalSort.java @@ -52,7 +52,7 @@ private TopologicalSort() { * @throws IllegalArgumentException if edges is null or contains invalid * vertices */ - public static int[] sort(int numVertices, List edges) { + public static int[] sort(int numVertices, Iterable edges) { if (edges == null) { throw new IllegalArgumentException("Edge list must not be null"); } diff --git a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java index 6ef853ec48f0..7eed902bdbec 100644 --- a/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java +++ b/src/test/java/com/thealgorithms/graph/TopologicalSortTest.java @@ -6,6 +6,7 @@ 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.DisplayName; @@ -16,8 +17,11 @@ class TopologicalSortTest { @Test @DisplayName("Simple DAG returns correct ordering") void simpleDAG() { - List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 0, 2 }, new int[] { 1, 3 }, - new int[] { 2, 3 }); + List edges = new ArrayList<>(); + edges.add(new int[] { 0, 1 }); + edges.add(new int[] { 0, 2 }); + edges.add(new int[] { 1, 3 }); + edges.add(new int[] { 2, 3 }); int[] result = TopologicalSort.sort(4, edges); assertArrayEquals(new int[] { 0, 1, 2, 3 }, result); } @@ -25,7 +29,7 @@ void simpleDAG() { @Test @DisplayName("Empty graph returns valid ordering") void emptyGraph() { - List edges = Arrays.asList(); + List edges = new ArrayList<>(); int[] result = TopologicalSort.sort(3, edges); assertEquals(3, result.length); // Any permutation is valid for empty graph @@ -35,7 +39,10 @@ void emptyGraph() { @Test @DisplayName("Graph with cycle returns null") void graphWithCycle() { - List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 1, 2 }, new int[] { 2, 0 }); + List edges = new ArrayList<>(); + edges.add(new int[] { 0, 1 }); + edges.add(new int[] { 1, 2 }); + edges.add(new int[] { 2, 0 }); assertNull(TopologicalSort.sort(3, edges)); } @@ -44,11 +51,11 @@ void graphWithCycle() { void coursePrerequisites() { // Example: Course prerequisites where edge [a,b] means course a must be taken // before b - List edges = Arrays.asList(new int[] { 1, 0 }, // Calculus I -> Calculus II - new int[] { 2, 0 }, // Linear Algebra -> Calculus II - new int[] { 1, 3 }, // Calculus I -> Differential Equations - new int[] { 2, 3 } // Linear Algebra -> Differential Equations - ); + List edges = new ArrayList<>(); + edges.add(new int[] { 1, 0 }); // Calculus I -> Calculus II + edges.add(new int[] { 2, 0 }); // Linear Algebra -> Calculus II + edges.add(new int[] { 1, 3 }); // Calculus I -> Differential Equations + edges.add(new int[] { 2, 3 }); // Linear Algebra -> Differential Equations List result = TopologicalSort.sortAndDetectCycle(4, edges); // Either [1,2,0,3] or [2,1,0,3] is valid assertEquals(4, result.size()); @@ -62,8 +69,8 @@ void coursePrerequisites() { @Test @DisplayName("Invalid vertex throws exception") void invalidVertex() { - List edges = Arrays.asList(new int[] { 0, 5 } // Vertex 5 is invalid for a graph with 3 vertices - ); + List edges = new ArrayList<>(); + edges.add(new int[] { 0, 5 }); // Vertex 5 is invalid for a graph with 3 vertices assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sort(3, edges)); } @@ -76,7 +83,10 @@ void nullEdgeList() { @Test @DisplayName("sortAndDetectCycle throws exception for cyclic graph") void detectCycleThrowsException() { - List edges = Arrays.asList(new int[] { 0, 1 }, new int[] { 1, 2 }, new int[] { 2, 0 }); + List edges = new ArrayList<>(); + edges.add(new int[] { 0, 1 }); + edges.add(new int[] { 1, 2 }); + edges.add(new int[] { 2, 0 }); assertThrows(IllegalArgumentException.class, () -> TopologicalSort.sortAndDetectCycle(3, edges)); } }