From 1b51e3e9886527e8be6d8a2bc968652744c42372 Mon Sep 17 00:00:00 2001 From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:48:12 +0530 Subject: [PATCH] Enhance docs, add more tests in `JohnsonsAlgorithm` (#5964) --- .../graphs/JohnsonsAlgorithm.java | 15 ++- .../graphs/JohnsonsAlgorithmTest.java | 100 ++++++++++-------- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java index 76c11f782..351bd5b00 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java @@ -21,17 +21,18 @@ import java.util.List; */ public final class JohnsonsAlgorithm { - // Constant representing infinity private static final double INF = Double.POSITIVE_INFINITY; - /** - * A private constructor to hide the implicit public one. - */ private JohnsonsAlgorithm() { } /** * Executes Johnson's algorithm on the given graph. + * Steps: + * 1. Add a new vertex to the graph and run Bellman-Ford to compute modified weights + * 2. t the graph using the modified weights + * 3. Run Dijkstra's algorithm for each vertex to compute the shortest paths + * The final result is a 2D array of shortest distances between all pairs of vertices. * * @param graph The input graph represented as an adjacency matrix. * @return A 2D array representing the shortest distances between all pairs of vertices. @@ -40,13 +41,10 @@ public final class JohnsonsAlgorithm { int numVertices = graph.length; double[][] edges = convertToEdgeList(graph); - // Step 1: Add a new vertex and run Bellman-Ford double[] modifiedWeights = bellmanFord(edges, numVertices); - // Step 2: Reweight the graph double[][] reweightedGraph = reweightGraph(graph, modifiedWeights); - // Step 3: Run Dijkstra's algorithm for each vertex double[][] shortestDistances = new double[numVertices][numVertices]; for (int source = 0; source < numVertices; source++) { shortestDistances[source] = dijkstra(reweightedGraph, source, modifiedWeights); @@ -74,7 +72,6 @@ public final class JohnsonsAlgorithm { } } - // Convert the List to a 2D array return edgeList.toArray(new double[0][]); } @@ -89,7 +86,7 @@ public final class JohnsonsAlgorithm { private static double[] bellmanFord(double[][] edges, int numVertices) { double[] dist = new double[numVertices + 1]; Arrays.fill(dist, INF); - dist[numVertices] = 0; // Distance to the new source vertex is 0 + dist[numVertices] = 0; // Add edges from the new vertex to all original vertices double[][] allEdges = Arrays.copyOf(edges, edges.length + numVertices); diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java index 0ae837cd9..7ea244920 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java @@ -23,114 +23,120 @@ class JohnsonsAlgorithmTest { */ @Test void testSimpleGraph() { - // Test case for a simple graph without negative edges double[][] graph = {{0, 4, INF, INF}, {INF, 0, 1, INF}, {INF, INF, 0, 2}, {INF, INF, INF, 0}}; - double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph); - double[][] expected = {{0, 4, 5, 7}, {INF, 0, 1, 3}, {INF, INF, 0, 2}, {INF, INF, INF, 0}}; - assertArrayEquals(expected, result); } /** - * Tests Johnson's Algorithm on a graph with negative edges but no - * negative weight cycles. Verifies the algorithm handles negative - * edge weights correctly. + * Tests Johnson's Algorithm on a graph with negative edges but no negative weight cycles. */ @Test void testGraphWithNegativeEdges() { - // Graph with negative edges but no negative weight cycles double[][] graph = {{0, -1, 4}, {INF, 0, 3}, {INF, INF, 0}}; - double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph); - double[][] expected = {{0, INF, 4}, {INF, 0, 3}, {INF, INF, 0}}; - assertArrayEquals(expected, result); } /** - * Tests the behavior of Johnson's Algorithm on a graph with a negative - * weight cycle. Expects an IllegalArgumentException to be thrown - * due to the presence of the cycle. + * Tests Johnson's Algorithm on a graph with a negative weight cycle. */ @Test void testNegativeWeightCycle() { - // Graph with a negative weight cycle double[][] graph = {{0, 1, INF}, {INF, 0, -1}, {-1, INF, 0}}; - - // Johnson's algorithm should throw an exception when a negative cycle is detected - assertThrows(IllegalArgumentException.class, () -> { JohnsonsAlgorithm.johnsonAlgorithm(graph); }); + assertThrows(IllegalArgumentException.class, () -> JohnsonsAlgorithm.johnsonAlgorithm(graph)); } /** - * Tests Dijkstra's algorithm as a part of Johnson's algorithm implementation - * on a small graph. Verifies that the shortest path is correctly calculated. + * Tests Dijkstra's algorithm on a small graph as part of Johnson's Algorithm. */ @Test void testDijkstra() { - // Testing Dijkstra's algorithm with a small graph double[][] graph = {{0, 1, 2}, {INF, 0, 3}, {INF, INF, 0}}; - - double[] modifiedWeights = {0, 0, 0}; // No reweighting in this simple case - + double[] modifiedWeights = {0, 0, 0}; double[] result = JohnsonsAlgorithm.dijkstra(graph, 0, modifiedWeights); double[] expected = {0, 1, 2}; - assertArrayEquals(expected, result); } /** * Tests the conversion of an adjacency matrix to an edge list. - * Verifies that the conversion process generates the correct edge list. */ @Test void testEdgeListConversion() { - // Test the conversion of adjacency matrix to edge list double[][] graph = {{0, 5, INF}, {INF, 0, 2}, {INF, INF, 0}}; - - // Running convertToEdgeList double[][] edges = JohnsonsAlgorithm.convertToEdgeList(graph); - - // Expected edge list: (0 -> 1, weight 5), (1 -> 2, weight 2) double[][] expected = {{0, 1, 5}, {1, 2, 2}}; - - // Verify the edge list matches the expected values assertArrayEquals(expected, edges); } /** - * Tests the reweighting of a graph as a part of Johnson's Algorithm. - * Verifies that the reweighted graph produces correct results. + * Tests the reweighting of a graph. */ @Test void testReweightGraph() { - // Test reweighting of the graph double[][] graph = {{0, 2, 9}, {INF, 0, 1}, {INF, INF, 0}}; - double[] modifiedWeights = {1, 2, 3}; // Arbitrary weight function - + double[] modifiedWeights = {1, 2, 3}; double[][] reweightedGraph = JohnsonsAlgorithm.reweightGraph(graph, modifiedWeights); - - // Expected reweighted graph: double[][] expected = {{0, 1, 7}, {INF, 0, 0}, {INF, INF, 0}}; - assertArrayEquals(expected, reweightedGraph); } /** - * Tests the minDistance method used in Dijkstra's algorithm to find - * the vertex with the minimum distance that has not yet been visited. + * Tests the minDistance method used in Dijkstra's algorithm. */ @Test void testMinDistance() { - // Test minDistance method double[] dist = {INF, 3, 1, INF}; boolean[] visited = {false, false, false, false}; - int minIndex = JohnsonsAlgorithm.minDistance(dist, visited); - - // The vertex with minimum distance is vertex 2 with a distance of 1 assertEquals(2, minIndex); } + + /** + * Tests Johnson's Algorithm on a graph where all vertices are disconnected. + */ + @Test + void testDisconnectedGraph() { + double[][] graph = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}}; + double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph); + double[][] expected = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}}; + assertArrayEquals(expected, result); + } + + /** + * Tests Johnson's Algorithm on a fully connected graph. + */ + @Test + void testFullyConnectedGraph() { + double[][] graph = {{0, 1, 2}, {1, 0, 1}, {2, 1, 0}}; + double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph); + double[][] expected = {{0, 1, 2}, {1, 0, 1}, {2, 1, 0}}; + assertArrayEquals(expected, result); + } + + /** + * Tests Dijkstra's algorithm on a graph with multiple shortest paths. + */ + @Test + void testDijkstraMultipleShortestPaths() { + double[][] graph = {{0, 1, 2, INF}, {INF, 0, INF, 1}, {INF, INF, 0, 1}, {INF, INF, INF, 0}}; + double[] modifiedWeights = {0, 0, 0, 0}; + double[] result = JohnsonsAlgorithm.dijkstra(graph, 0, modifiedWeights); + double[] expected = {0, 1, 2, 2}; + assertArrayEquals(expected, result); + } + + /** + * Tests Johnson's Algorithm with a graph where all edge weights are zero. + */ + @Test + void testGraphWithZeroWeights() { + double[][] graph = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph); + double[][] expected = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}}; + assertArrayEquals(expected, result); + } }