Skip to content

Commit 13be250

Browse files
authored
Enhance docs, add tests in KahnsAlgorithm (#5965)
1 parent 3a9a2c4 commit 13be250

File tree

3 files changed

+134
-28
lines changed

3 files changed

+134
-28
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@
810810
* [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java)
811811
* [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java)
812812
* [JohnsonsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java)
813+
* [KahnsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithmTest.java)
813814
* [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java)
814815
* [TarjansAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithmTest.java)
815816
* [WelshPowellTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java)

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

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,96 +9,120 @@
99
import java.util.Set;
1010

1111
/**
12-
* A class that represents the adjaceny list of a graph
12+
* A class representing the adjacency list of a directed graph. The adjacency list
13+
* maintains a mapping of vertices to their adjacent vertices.
14+
*
15+
* @param <E> the type of vertices, extending Comparable to ensure that vertices
16+
* can be compared
1317
*/
1418
class AdjacencyList<E extends Comparable<E>> {
1519

1620
Map<E, ArrayList<E>> adj;
1721

22+
/**
23+
* Constructor to initialize the adjacency list.
24+
*/
1825
AdjacencyList() {
19-
adj = new LinkedHashMap<E, ArrayList<E>>();
26+
adj = new LinkedHashMap<>();
2027
}
2128

2229
/**
23-
* This function adds an Edge to the adjaceny list
30+
* Adds a directed edge from one vertex to another in the adjacency list.
31+
* If the vertex does not exist, it will be added to the list.
2432
*
25-
* @param from , the vertex the edge is from
26-
* @param to, the vertex the edge is going to
33+
* @param from the starting vertex of the directed edge
34+
* @param to the destination vertex of the directed edge
2735
*/
2836
void addEdge(E from, E to) {
29-
try {
30-
adj.get(from).add(to);
31-
} catch (Exception E) {
32-
adj.put(from, new ArrayList<E>());
33-
adj.get(from).add(to);
37+
if (!adj.containsKey(from)) {
38+
adj.put(from, new ArrayList<>());
3439
}
40+
adj.get(from).add(to);
3541
if (!adj.containsKey(to)) {
36-
adj.put(to, new ArrayList<E>());
42+
adj.put(to, new ArrayList<>());
3743
}
3844
}
3945

4046
/**
41-
* @param v, A vertex in a graph
42-
* @return returns an ArrayList of all the adjacents of vertex v
47+
* Retrieves the list of adjacent vertices for a given vertex.
48+
*
49+
* @param v the vertex whose adjacent vertices are to be fetched
50+
* @return an ArrayList of adjacent vertices for vertex v
4351
*/
4452
ArrayList<E> getAdjacents(E v) {
4553
return adj.get(v);
4654
}
4755

4856
/**
49-
* @return returns a set of all vertices in the graph
57+
* Retrieves the set of all vertices present in the graph.
58+
*
59+
* @return a set containing all vertices in the graph
5060
*/
5161
Set<E> getVertices() {
5262
return adj.keySet();
5363
}
5464
}
5565

66+
/**
67+
* A class that performs topological sorting on a directed graph using Kahn's algorithm.
68+
*
69+
* @param <E> the type of vertices, extending Comparable to ensure that vertices
70+
* can be compared
71+
*/
5672
class TopologicalSort<E extends Comparable<E>> {
5773

5874
AdjacencyList<E> graph;
5975
Map<E, Integer> inDegree;
6076

77+
/**
78+
* Constructor to initialize the topological sorting class with a given graph.
79+
*
80+
* @param graph the directed graph represented as an adjacency list
81+
*/
6182
TopologicalSort(AdjacencyList<E> graph) {
6283
this.graph = graph;
6384
}
6485

6586
/**
66-
* Calculates the in degree of all vertices
87+
* Calculates the in-degree of all vertices in the graph. The in-degree is
88+
* the number of edges directed into a vertex.
6789
*/
6890
void calculateInDegree() {
6991
inDegree = new HashMap<>();
7092
for (E vertex : graph.getVertices()) {
71-
if (!inDegree.containsKey(vertex)) {
72-
inDegree.put(vertex, 0);
73-
}
93+
inDegree.putIfAbsent(vertex, 0);
7494
for (E adjacent : graph.getAdjacents(vertex)) {
75-
try {
76-
inDegree.put(adjacent, inDegree.get(adjacent) + 1);
77-
} catch (Exception e) {
78-
inDegree.put(adjacent, 1);
79-
}
95+
inDegree.put(adjacent, inDegree.getOrDefault(adjacent, 0) + 1);
8096
}
8197
}
8298
}
8399

84100
/**
85-
* Returns an ArrayList with vertices arranged in topological order
101+
* Returns an ArrayList containing the vertices of the graph arranged in
102+
* topological order. Topological sorting ensures that for any directed edge
103+
* (u, v), vertex u appears before vertex v in the ordering.
104+
*
105+
* @return an ArrayList of vertices in topological order
106+
* @throws IllegalStateException if the graph contains a cycle
86107
*/
87108
ArrayList<E> topSortOrder() {
88109
calculateInDegree();
89-
Queue<E> q = new LinkedList<E>();
110+
Queue<E> q = new LinkedList<>();
90111

91-
for (final var entry : inDegree.entrySet()) {
112+
for (var entry : inDegree.entrySet()) {
92113
if (entry.getValue() == 0) {
93114
q.add(entry.getKey());
94115
}
95116
}
96117

97118
ArrayList<E> answer = new ArrayList<>();
119+
int processedVertices = 0;
98120

99121
while (!q.isEmpty()) {
100122
E current = q.poll();
101123
answer.add(current);
124+
processedVertices++;
125+
102126
for (E adjacent : graph.getAdjacents(current)) {
103127
inDegree.put(adjacent, inDegree.get(adjacent) - 1);
104128
if (inDegree.get(adjacent) == 0) {
@@ -107,12 +131,16 @@ ArrayList<E> topSortOrder() {
107131
}
108132
}
109133

134+
if (processedVertices != graph.getVertices().size()) {
135+
throw new IllegalStateException("Graph contains a cycle, topological sort not possible");
136+
}
137+
110138
return answer;
111139
}
112140
}
113141

114142
/**
115-
* A driver class that sorts a given graph in topological order.
143+
* A driver class that sorts a given graph in topological order using Kahn's algorithm.
116144
*/
117145
public final class KahnsAlgorithm {
118146
private KahnsAlgorithm() {
@@ -130,7 +158,7 @@ public static void main(String[] args) {
130158

131159
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
132160

133-
// Printing the order
161+
// Printing the topological order
134162
for (String s : topSort.topSortOrder()) {
135163
System.out.print(s + " ");
136164
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.util.ArrayList;
7+
import org.junit.jupiter.api.Test;
8+
9+
class KahnsAlgorithmTest {
10+
11+
@Test
12+
void testBasicGraph() {
13+
// Test case with a basic directed acyclic graph (DAG)
14+
AdjacencyList<String> graph = new AdjacencyList<>();
15+
graph.addEdge("a", "b");
16+
graph.addEdge("c", "a");
17+
graph.addEdge("a", "d");
18+
graph.addEdge("b", "d");
19+
20+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
21+
ArrayList<String> result = topSort.topSortOrder();
22+
23+
String[] expectedOrder = {"c", "a", "b", "d"};
24+
assertArrayEquals(expectedOrder, result.toArray());
25+
}
26+
27+
@Test
28+
void testGraphWithMultipleSources() {
29+
// Test case where graph has multiple independent sources
30+
AdjacencyList<String> graph = new AdjacencyList<>();
31+
graph.addEdge("a", "c");
32+
graph.addEdge("b", "c");
33+
34+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
35+
ArrayList<String> result = topSort.topSortOrder();
36+
37+
String[] expectedOrder = {"a", "b", "c"};
38+
assertArrayEquals(expectedOrder, result.toArray());
39+
}
40+
41+
@Test
42+
void testDisconnectedGraph() {
43+
// Test case for disconnected graph
44+
AdjacencyList<String> graph = new AdjacencyList<>();
45+
graph.addEdge("a", "b");
46+
graph.addEdge("c", "d");
47+
48+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
49+
ArrayList<String> result = topSort.topSortOrder();
50+
51+
String[] expectedOrder = {"a", "c", "b", "d"};
52+
assertArrayEquals(expectedOrder, result.toArray());
53+
}
54+
55+
@Test
56+
void testGraphWithCycle() {
57+
// Test case for a graph with a cycle - topological sorting is not possible
58+
AdjacencyList<String> graph = new AdjacencyList<>();
59+
graph.addEdge("a", "b");
60+
graph.addEdge("b", "c");
61+
graph.addEdge("c", "a");
62+
63+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
64+
65+
assertThrows(IllegalStateException.class, () -> topSort.topSortOrder());
66+
}
67+
68+
@Test
69+
void testSingleNodeGraph() {
70+
AdjacencyList<String> graph = new AdjacencyList<>();
71+
graph.addEdge("a", "a"); // self-loop
72+
73+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
74+
75+
assertThrows(IllegalStateException.class, () -> topSort.topSortOrder());
76+
}
77+
}

0 commit comments

Comments
 (0)