Skip to content

Commit 832eeb9

Browse files
committed
refactor: Enhance docs, add tests in KahnsAlgorithm
1 parent be0b1d5 commit 832eeb9

File tree

2 files changed

+128
-28
lines changed

2 files changed

+128
-28
lines changed

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

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,86 +9,106 @@
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
86106
*/
87107
ArrayList<E> topSortOrder() {
88108
calculateInDegree();
89-
Queue<E> q = new LinkedList<E>();
109+
Queue<E> q = new LinkedList<>();
90110

91-
for (final var entry : inDegree.entrySet()) {
111+
for (var entry : inDegree.entrySet()) {
92112
if (entry.getValue() == 0) {
93113
q.add(entry.getKey());
94114
}
@@ -112,7 +132,7 @@ ArrayList<E> topSortOrder() {
112132
}
113133

114134
/**
115-
* A driver class that sorts a given graph in topological order.
135+
* A driver class that sorts a given graph in topological order using Kahn's algorithm.
116136
*/
117137
public final class KahnsAlgorithm {
118138
private KahnsAlgorithm() {
@@ -130,7 +150,7 @@ public static void main(String[] args) {
130150

131151
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
132152

133-
// Printing the order
153+
// Printing the topological order
134154
for (String s : topSort.topSortOrder()) {
135155
System.out.print(s + " ");
136156
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
// Test case for a graph with a single node
71+
AdjacencyList<String> graph = new AdjacencyList<>();
72+
graph.addEdge("a", "a"); // self-loop
73+
74+
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
75+
ArrayList<String> result = topSort.topSortOrder();
76+
77+
String[] expectedOrder = {};
78+
assertArrayEquals(expectedOrder, result.toArray());
79+
}
80+
}

0 commit comments

Comments
 (0)