Skip to content

Commit 1b51e3e

Browse files
authored
Enhance docs, add more tests in JohnsonsAlgorithm (#5964)
1 parent be0b1d5 commit 1b51e3e

File tree

2 files changed

+59
-56
lines changed

2 files changed

+59
-56
lines changed

src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java

+6-9
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@
2121
*/
2222
public final class JohnsonsAlgorithm {
2323

24-
// Constant representing infinity
2524
private static final double INF = Double.POSITIVE_INFINITY;
2625

27-
/**
28-
* A private constructor to hide the implicit public one.
29-
*/
3026
private JohnsonsAlgorithm() {
3127
}
3228

3329
/**
3430
* Executes Johnson's algorithm on the given graph.
31+
* Steps:
32+
* 1. Add a new vertex to the graph and run Bellman-Ford to compute modified weights
33+
* 2. t the graph using the modified weights
34+
* 3. Run Dijkstra's algorithm for each vertex to compute the shortest paths
35+
* The final result is a 2D array of shortest distances between all pairs of vertices.
3536
*
3637
* @param graph The input graph represented as an adjacency matrix.
3738
* @return A 2D array representing the shortest distances between all pairs of vertices.
@@ -40,13 +41,10 @@ public static double[][] johnsonAlgorithm(double[][] graph) {
4041
int numVertices = graph.length;
4142
double[][] edges = convertToEdgeList(graph);
4243

43-
// Step 1: Add a new vertex and run Bellman-Ford
4444
double[] modifiedWeights = bellmanFord(edges, numVertices);
4545

46-
// Step 2: Reweight the graph
4746
double[][] reweightedGraph = reweightGraph(graph, modifiedWeights);
4847

49-
// Step 3: Run Dijkstra's algorithm for each vertex
5048
double[][] shortestDistances = new double[numVertices][numVertices];
5149
for (int source = 0; source < numVertices; source++) {
5250
shortestDistances[source] = dijkstra(reweightedGraph, source, modifiedWeights);
@@ -74,7 +72,6 @@ public static double[][] convertToEdgeList(double[][] graph) {
7472
}
7573
}
7674

77-
// Convert the List to a 2D array
7875
return edgeList.toArray(new double[0][]);
7976
}
8077

@@ -89,7 +86,7 @@ public static double[][] convertToEdgeList(double[][] graph) {
8986
private static double[] bellmanFord(double[][] edges, int numVertices) {
9087
double[] dist = new double[numVertices + 1];
9188
Arrays.fill(dist, INF);
92-
dist[numVertices] = 0; // Distance to the new source vertex is 0
89+
dist[numVertices] = 0;
9390

9491
// Add edges from the new vertex to all original vertices
9592
double[][] allEdges = Arrays.copyOf(edges, edges.length + numVertices);

src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java

+53-47
Original file line numberDiff line numberDiff line change
@@ -23,114 +23,120 @@ class JohnsonsAlgorithmTest {
2323
*/
2424
@Test
2525
void testSimpleGraph() {
26-
// Test case for a simple graph without negative edges
2726
double[][] graph = {{0, 4, INF, INF}, {INF, 0, 1, INF}, {INF, INF, 0, 2}, {INF, INF, INF, 0}};
28-
2927
double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
30-
3128
double[][] expected = {{0, 4, 5, 7}, {INF, 0, 1, 3}, {INF, INF, 0, 2}, {INF, INF, INF, 0}};
32-
3329
assertArrayEquals(expected, result);
3430
}
3531

3632
/**
37-
* Tests Johnson's Algorithm on a graph with negative edges but no
38-
* negative weight cycles. Verifies the algorithm handles negative
39-
* edge weights correctly.
33+
* Tests Johnson's Algorithm on a graph with negative edges but no negative weight cycles.
4034
*/
4135
@Test
4236
void testGraphWithNegativeEdges() {
43-
// Graph with negative edges but no negative weight cycles
4437
double[][] graph = {{0, -1, 4}, {INF, 0, 3}, {INF, INF, 0}};
45-
4638
double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
47-
4839
double[][] expected = {{0, INF, 4}, {INF, 0, 3}, {INF, INF, 0}};
49-
5040
assertArrayEquals(expected, result);
5141
}
5242

5343
/**
54-
* Tests the behavior of Johnson's Algorithm on a graph with a negative
55-
* weight cycle. Expects an IllegalArgumentException to be thrown
56-
* due to the presence of the cycle.
44+
* Tests Johnson's Algorithm on a graph with a negative weight cycle.
5745
*/
5846
@Test
5947
void testNegativeWeightCycle() {
60-
// Graph with a negative weight cycle
6148
double[][] graph = {{0, 1, INF}, {INF, 0, -1}, {-1, INF, 0}};
62-
63-
// Johnson's algorithm should throw an exception when a negative cycle is detected
64-
assertThrows(IllegalArgumentException.class, () -> { JohnsonsAlgorithm.johnsonAlgorithm(graph); });
49+
assertThrows(IllegalArgumentException.class, () -> JohnsonsAlgorithm.johnsonAlgorithm(graph));
6550
}
6651

6752
/**
68-
* Tests Dijkstra's algorithm as a part of Johnson's algorithm implementation
69-
* on a small graph. Verifies that the shortest path is correctly calculated.
53+
* Tests Dijkstra's algorithm on a small graph as part of Johnson's Algorithm.
7054
*/
7155
@Test
7256
void testDijkstra() {
73-
// Testing Dijkstra's algorithm with a small graph
7457
double[][] graph = {{0, 1, 2}, {INF, 0, 3}, {INF, INF, 0}};
75-
76-
double[] modifiedWeights = {0, 0, 0}; // No reweighting in this simple case
77-
58+
double[] modifiedWeights = {0, 0, 0};
7859
double[] result = JohnsonsAlgorithm.dijkstra(graph, 0, modifiedWeights);
7960
double[] expected = {0, 1, 2};
80-
8161
assertArrayEquals(expected, result);
8262
}
8363

8464
/**
8565
* Tests the conversion of an adjacency matrix to an edge list.
86-
* Verifies that the conversion process generates the correct edge list.
8766
*/
8867
@Test
8968
void testEdgeListConversion() {
90-
// Test the conversion of adjacency matrix to edge list
9169
double[][] graph = {{0, 5, INF}, {INF, 0, 2}, {INF, INF, 0}};
92-
93-
// Running convertToEdgeList
9470
double[][] edges = JohnsonsAlgorithm.convertToEdgeList(graph);
95-
96-
// Expected edge list: (0 -> 1, weight 5), (1 -> 2, weight 2)
9771
double[][] expected = {{0, 1, 5}, {1, 2, 2}};
98-
99-
// Verify the edge list matches the expected values
10072
assertArrayEquals(expected, edges);
10173
}
10274

10375
/**
104-
* Tests the reweighting of a graph as a part of Johnson's Algorithm.
105-
* Verifies that the reweighted graph produces correct results.
76+
* Tests the reweighting of a graph.
10677
*/
10778
@Test
10879
void testReweightGraph() {
109-
// Test reweighting of the graph
11080
double[][] graph = {{0, 2, 9}, {INF, 0, 1}, {INF, INF, 0}};
111-
double[] modifiedWeights = {1, 2, 3}; // Arbitrary weight function
112-
81+
double[] modifiedWeights = {1, 2, 3};
11382
double[][] reweightedGraph = JohnsonsAlgorithm.reweightGraph(graph, modifiedWeights);
114-
115-
// Expected reweighted graph:
11683
double[][] expected = {{0, 1, 7}, {INF, 0, 0}, {INF, INF, 0}};
117-
11884
assertArrayEquals(expected, reweightedGraph);
11985
}
12086

12187
/**
122-
* Tests the minDistance method used in Dijkstra's algorithm to find
123-
* the vertex with the minimum distance that has not yet been visited.
88+
* Tests the minDistance method used in Dijkstra's algorithm.
12489
*/
12590
@Test
12691
void testMinDistance() {
127-
// Test minDistance method
12892
double[] dist = {INF, 3, 1, INF};
12993
boolean[] visited = {false, false, false, false};
130-
13194
int minIndex = JohnsonsAlgorithm.minDistance(dist, visited);
132-
133-
// The vertex with minimum distance is vertex 2 with a distance of 1
13495
assertEquals(2, minIndex);
13596
}
97+
98+
/**
99+
* Tests Johnson's Algorithm on a graph where all vertices are disconnected.
100+
*/
101+
@Test
102+
void testDisconnectedGraph() {
103+
double[][] graph = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}};
104+
double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
105+
double[][] expected = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}};
106+
assertArrayEquals(expected, result);
107+
}
108+
109+
/**
110+
* Tests Johnson's Algorithm on a fully connected graph.
111+
*/
112+
@Test
113+
void testFullyConnectedGraph() {
114+
double[][] graph = {{0, 1, 2}, {1, 0, 1}, {2, 1, 0}};
115+
double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
116+
double[][] expected = {{0, 1, 2}, {1, 0, 1}, {2, 1, 0}};
117+
assertArrayEquals(expected, result);
118+
}
119+
120+
/**
121+
* Tests Dijkstra's algorithm on a graph with multiple shortest paths.
122+
*/
123+
@Test
124+
void testDijkstraMultipleShortestPaths() {
125+
double[][] graph = {{0, 1, 2, INF}, {INF, 0, INF, 1}, {INF, INF, 0, 1}, {INF, INF, INF, 0}};
126+
double[] modifiedWeights = {0, 0, 0, 0};
127+
double[] result = JohnsonsAlgorithm.dijkstra(graph, 0, modifiedWeights);
128+
double[] expected = {0, 1, 2, 2};
129+
assertArrayEquals(expected, result);
130+
}
131+
132+
/**
133+
* Tests Johnson's Algorithm with a graph where all edge weights are zero.
134+
*/
135+
@Test
136+
void testGraphWithZeroWeights() {
137+
double[][] graph = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
138+
double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
139+
double[][] expected = {{0, INF, INF}, {INF, 0, INF}, {INF, INF, 0}};
140+
assertArrayEquals(expected, result);
141+
}
136142
}

0 commit comments

Comments
 (0)