Skip to content

Commit c552690

Browse files
committed
Master
This PR implements a DFS-based topological sorting algorithm for Directed Acyclic Graphs (DAGs) as requested in issue #6938.
1 parent 1c6026e commit c552690

File tree

2 files changed

+413
-0
lines changed

2 files changed

+413
-0
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import java.util.*;
4+
5+
/**
6+
* Topological Sorting using Depth-First Search (DFS)
7+
*
8+
* Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices
9+
* such that for every directed edge u -> v, vertex u comes before v in the ordering.
10+
*
11+
* Applications:
12+
* - Task scheduling with dependencies
13+
* - Build systems and compilation order
14+
* - Course prerequisite ordering
15+
* - Package dependency resolution
16+
*
17+
* Time Complexity: O(V + E) where V is vertices and E is edges
18+
* Space Complexity: O(V) for the stack and visited array
19+
*
20+
* @author Your Name
21+
*/
22+
public class TopologicalSortDFS {
23+
24+
private int vertices;
25+
private List<List<Integer>> adjList;
26+
27+
/**
28+
* Constructor to initialize the graph
29+
*
30+
* @param vertices Number of vertices in the graph
31+
*/
32+
public TopologicalSortDFS(int vertices) {
33+
this.vertices = vertices;
34+
adjList = new ArrayList<>(vertices);
35+
36+
for (int i = 0; i < vertices; i++) {
37+
adjList.add(new ArrayList<>());
38+
}
39+
}
40+
41+
/**
42+
* Add a directed edge from source to destination
43+
*
44+
* @param src Source vertex
45+
* @param dest Destination vertex
46+
*/
47+
public void addEdge(int src, int dest) {
48+
if (src >= 0 && src < vertices && dest >= 0 && dest < vertices) {
49+
adjList.get(src).add(dest);
50+
} else {
51+
throw new IllegalArgumentException("Invalid vertex index");
52+
}
53+
}
54+
55+
/**
56+
* Recursive DFS helper function for topological sorting
57+
*
58+
* @param vertex Current vertex being visited
59+
* @param visited Array to track visited vertices
60+
* @param stack Stack to store the topological order
61+
*/
62+
private void topologicalSortUtil(int vertex, boolean[] visited, Stack<Integer> stack) {
63+
// Mark current vertex as visited
64+
visited[vertex] = true;
65+
66+
// Recursively visit all adjacent vertices
67+
for (Integer neighbor : adjList.get(vertex)) {
68+
if (!visited[neighbor]) {
69+
topologicalSortUtil(neighbor, visited, stack);
70+
}
71+
}
72+
73+
// Push current vertex to stack after visiting all neighbors
74+
// This ensures vertices are in reverse topological order in the stack
75+
stack.push(vertex);
76+
}
77+
78+
/**
79+
* Perform topological sort on the graph
80+
*
81+
* @return List of vertices in topological order, or null if cycle detected
82+
*/
83+
public List<Integer> topologicalSort() {
84+
// Check if graph has cycles
85+
if (hasCycle()) {
86+
return null; // Topological sort not possible for cyclic graphs
87+
}
88+
89+
Stack<Integer> stack = new Stack<>();
90+
boolean[] visited = new boolean[vertices];
91+
92+
// Call the recursive helper function for all unvisited vertices
93+
for (int i = 0; i < vertices; i++) {
94+
if (!visited[i]) {
95+
topologicalSortUtil(i, visited, stack);
96+
}
97+
}
98+
99+
// Pop all vertices from stack to get topological order
100+
List<Integer> result = new ArrayList<>();
101+
while (!stack.isEmpty()) {
102+
result.add(stack.pop());
103+
}
104+
105+
return result;
106+
}
107+
108+
/**
109+
* Check if the graph contains a cycle using DFS
110+
*
111+
* @return true if cycle exists, false otherwise
112+
*/
113+
public boolean hasCycle() {
114+
boolean[] visited = new boolean[vertices];
115+
boolean[] recStack = new boolean[vertices];
116+
117+
// Check for cycle starting from each vertex
118+
for (int i = 0; i < vertices; i++) {
119+
if (hasCycleUtil(i, visited, recStack)) {
120+
return true;
121+
}
122+
}
123+
124+
return false;
125+
}
126+
127+
/**
128+
* Helper function to detect cycle using DFS
129+
*
130+
* @param vertex Current vertex
131+
* @param visited Array to track visited vertices
132+
* @param recStack Recursion stack to track vertices in current path
133+
* @return true if cycle detected, false otherwise
134+
*/
135+
private boolean hasCycleUtil(int vertex, boolean[] visited, boolean[] recStack) {
136+
// If vertex is in recursion stack, cycle detected
137+
if (recStack[vertex]) {
138+
return true;
139+
}
140+
141+
// If already visited and not in recursion stack, no cycle from this vertex
142+
if (visited[vertex]) {
143+
return false;
144+
}
145+
146+
// Mark vertex as visited and add to recursion stack
147+
visited[vertex] = true;
148+
recStack[vertex] = true;
149+
150+
// Check all neighbors
151+
for (Integer neighbor : adjList.get(vertex)) {
152+
if (hasCycleUtil(neighbor, visited, recStack)) {
153+
return true;
154+
}
155+
}
156+
157+
// Remove vertex from recursion stack before backtracking
158+
recStack[vertex] = false;
159+
160+
return false;
161+
}
162+
163+
/**
164+
* Get the adjacency list representation of the graph
165+
*
166+
* @return Adjacency list
167+
*/
168+
public List<List<Integer>> getAdjList() {
169+
return adjList;
170+
}
171+
172+
/**
173+
* Main method with example usage
174+
*/
175+
public static void main(String[] args) {
176+
// Example 1: Valid DAG
177+
System.out.println("Example 1: Course Prerequisites");
178+
TopologicalSortDFS graph1 = new TopologicalSortDFS(6);
179+
180+
// Course dependencies: must take course X before course Y
181+
graph1.addEdge(5, 2); // Course 5 before Course 2
182+
graph1.addEdge(5, 0); // Course 5 before Course 0
183+
graph1.addEdge(4, 0); // Course 4 before Course 0
184+
graph1.addEdge(4, 1); // Course 4 before Course 1
185+
graph1.addEdge(2, 3); // Course 2 before Course 3
186+
graph1.addEdge(3, 1); // Course 3 before Course 1
187+
188+
List<Integer> result1 = graph1.topologicalSort();
189+
if (result1 != null) {
190+
System.out.println("Topological Order: " + result1);
191+
} else {
192+
System.out.println("Cycle detected! Topological sort not possible.");
193+
}
194+
195+
// Example 2: Cyclic Graph
196+
System.out.println("\nExample 2: Cyclic Graph");
197+
TopologicalSortDFS graph2 = new TopologicalSortDFS(3);
198+
graph2.addEdge(0, 1);
199+
graph2.addEdge(1, 2);
200+
graph2.addEdge(2, 0); // Creates a cycle
201+
202+
List<Integer> result2 = graph2.topologicalSort();
203+
if (result2 != null) {
204+
System.out.println("Topological Order: " + result2);
205+
} else {
206+
System.out.println("Cycle detected! Topological sort not possible.");
207+
}
208+
209+
// Example 3: Build System Dependencies
210+
System.out.println("\nExample 3: Build System");
211+
TopologicalSortDFS graph3 = new TopologicalSortDFS(4);
212+
graph3.addEdge(0, 1); // Module 0 must be built before Module 1
213+
graph3.addEdge(0, 2); // Module 0 must be built before Module 2
214+
graph3.addEdge(1, 3); // Module 1 must be built before Module 3
215+
graph3.addEdge(2, 3); // Module 2 must be built before Module 3
216+
217+
List<Integer> result3 = graph3.topologicalSort();
218+
if (result3 != null) {
219+
System.out.println("Build Order: " + result3);
220+
} else {
221+
System.out.println("Cycle detected! Build order not possible.");
222+
}
223+
}
224+
}

0 commit comments

Comments
 (0)