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 ("\n Example 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 ("\n Example 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