|
| 1 | +<h1 align='center'>Topological - Sort - Using - DFS</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Topological Sort using DFS](https://www.geeksforgeeks.org/topological-sorting/) |
| 6 | + |
| 7 | +### **What is Topological Sort?** |
| 8 | +- Topological sorting is a linear ordering of vertices in a **directed acyclic graph (DAG)** such that for every directed edge `U → V`, vertex `U` appears before vertex `V` in the ordering. |
| 9 | +- **Applications**: |
| 10 | + 1. Task scheduling (e.g., compiling tasks with dependencies). |
| 11 | + 2. Course prerequisite planning. |
| 12 | + 3. Resolving symbol dependencies in linkers. |
| 13 | + |
| 14 | + |
| 15 | +#### **Example: Understanding Topological Sort** |
| 16 | + |
| 17 | +#### Graph: |
| 18 | +Consider a directed graph with 4 nodes and the following edges: |
| 19 | +``` |
| 20 | +0 → 1 |
| 21 | +1 → 2 |
| 22 | +3 → 1 |
| 23 | +3 → 2 |
| 24 | +``` |
| 25 | + |
| 26 | +#### Representation: |
| 27 | +**Adjacency List**: |
| 28 | +``` |
| 29 | +0 → [1] |
| 30 | +1 → [2] |
| 31 | +3 → [1, 2] |
| 32 | +``` |
| 33 | + |
| 34 | +#### **Steps for Topological Sort**: |
| 35 | +1. Identify nodes with no incoming edges (start points). |
| 36 | +2. Use **Depth First Search (DFS)** to explore the graph. |
| 37 | +3. When a node has no more unvisited neighbors, add it to the stack. |
| 38 | +4. Continue until all nodes are visited. |
| 39 | +5. The stack contains the nodes in **reverse topological order**. |
| 40 | + |
| 41 | +**Result for the given graph**: |
| 42 | +- One valid topological ordering: `3 0 1 2`. |
| 43 | + |
| 44 | + |
| 45 | +### **Approach: DFS for Topological Sorting** |
| 46 | + |
| 47 | +#### **Key Steps**: |
| 48 | +1. **Initialization**: |
| 49 | + - Maintain a `visited` array to track visited nodes. |
| 50 | + - Use a stack to store the topological order. |
| 51 | + |
| 52 | +2. **DFS Traversal**: |
| 53 | + - Visit all neighbors of the current node recursively. |
| 54 | + - When there are no more neighbors, add the current node to the stack. |
| 55 | + |
| 56 | +3. **Retrieve Order**: |
| 57 | + - Pop all elements from the stack to get the topological order. |
| 58 | + |
| 59 | + |
| 60 | +### Problem Solution |
| 61 | +```cpp |
| 62 | +#include <bits/stdc++.h> |
| 63 | +using namespace std; |
| 64 | + |
| 65 | +// Function to perform DFS and topological sorting |
| 66 | +void topologicalSortUtil(int node, vector<vector<int> >& adj, vector<bool>& visited, stack<int>& Stack){ |
| 67 | + // Mark the current node as visited |
| 68 | + visited[node] = true; |
| 69 | + |
| 70 | + // Recur for all adjacent vertices |
| 71 | + for (auto neighbour : adj[node]) if (!visited[neighbour]) topologicalSortUtil(neighbour, adj, visited, Stack); |
| 72 | + |
| 73 | + // Push current vertex to stack which stores the result |
| 74 | + Stack.push(node); |
| 75 | +} |
| 76 | + |
| 77 | +// Function to perform Topological Sort |
| 78 | +void topologicalSort(vector<vector<int> >& adj, int V){ |
| 79 | + stack<int> Stack; // Stack to store the result |
| 80 | + vector<bool> visited(V, false); |
| 81 | + |
| 82 | + // Call the recursive helper function to store |
| 83 | + // Topological Sort starting from all vertices one by |
| 84 | + // one |
| 85 | + for (int i = 0; i < V; i++) if (!visited[i]) topologicalSortUtil(i, adj, visited, Stack); |
| 86 | + |
| 87 | + // Print contents of stack |
| 88 | + while (!Stack.empty()) { |
| 89 | + cout << Stack.top() << " "; |
| 90 | + Stack.pop(); |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +int main() |
| 95 | +{ |
| 96 | + |
| 97 | + // Number of nodes |
| 98 | + int V = 4; |
| 99 | + |
| 100 | + // Edges |
| 101 | + vector<vector<int> > edges = {{0, 1}, {1, 2}, {3, 1}, {3, 2}}; |
| 102 | + |
| 103 | + // Graph represented as an adjacency list |
| 104 | + vector<vector<int> > adj(V); |
| 105 | + |
| 106 | + for (auto i : edges) adj[i[0]].push_back(i[1]); |
| 107 | + |
| 108 | + cout << "Topological sorting of the graph: "; |
| 109 | + topologicalSort(adj, V); |
| 110 | + |
| 111 | + return 0; |
| 112 | +} |
| 113 | +``` |
| 114 | +
|
| 115 | +## Problem Solution Explanation |
| 116 | +
|
| 117 | +Let's go through the **Topological Sort code** line by line and explain each part with examples. |
| 118 | +
|
| 119 | +```cpp |
| 120 | +#include <bits/stdc++.h> |
| 121 | +using namespace std; |
| 122 | +``` |
| 123 | + |
| 124 | +- **`#include <bits/stdc++.h>`**: |
| 125 | + - Includes all standard C++ libraries (e.g., iostream, vector, stack). |
| 126 | + - Simplifies development by allowing us to use containers like `vector`, `stack`, etc. |
| 127 | + |
| 128 | +- **`using namespace std;`**: |
| 129 | + - Avoids the need to prefix standard library functions and types (e.g., `std::vector`, `std::cout`). |
| 130 | + |
| 131 | + |
| 132 | +### **Helper Function: `topologicalSortUtil`** |
| 133 | + |
| 134 | +```cpp |
| 135 | +void topologicalSortUtil(int node, vector<vector<int>>& adj, vector<bool>& visited, stack<int>& Stack) { |
| 136 | + visited[node] = true; |
| 137 | +``` |
| 138 | +
|
| 139 | +- **`void topologicalSortUtil(...)`**: |
| 140 | + - Helper function to perform **DFS**. |
| 141 | + - **Parameters**: |
| 142 | + 1. `node`: The current node being processed. |
| 143 | + 2. `adj`: Adjacency list representation of the graph. |
| 144 | + 3. `visited`: Keeps track of nodes already visited. |
| 145 | + 4. `Stack`: Stores nodes in reverse topological order. |
| 146 | +
|
| 147 | +- **`visited[node] = true;`**: |
| 148 | + - Marks the current node as visited to prevent revisiting. |
| 149 | +
|
| 150 | +
|
| 151 | +
|
| 152 | +```cpp |
| 153 | + for (auto neighbour : adj[node]) { |
| 154 | + if (!visited[neighbour]) { |
| 155 | + topologicalSortUtil(neighbour, adj, visited, Stack); |
| 156 | + } |
| 157 | + } |
| 158 | +``` |
| 159 | + |
| 160 | +- **`for (auto neighbour : adj[node]) {...}`**: |
| 161 | + - Iterates over all neighbors of the current node using the adjacency list. |
| 162 | + - **`if (!visited[neighbour])`**: |
| 163 | + - Checks if the neighbor is unvisited. If so, calls `topologicalSortUtil` recursively. |
| 164 | + |
| 165 | +**Example**: |
| 166 | +For the graph: |
| 167 | +``` |
| 168 | +0 → [1] |
| 169 | +1 → [2] |
| 170 | +``` |
| 171 | +If `node = 0`, then `adj[0] = [1]`. The function recursively processes `1`. |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | +```cpp |
| 176 | + Stack.push(node); |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +- **`Stack.push(node);`**: |
| 181 | + - Once all neighbors of the node are visited, the node is pushed to the stack. |
| 182 | + - This ensures that nodes with no dependencies are processed first. |
| 183 | + |
| 184 | +**Example**: |
| 185 | +For the graph: |
| 186 | +``` |
| 187 | +0 → [1] |
| 188 | +1 → [2] |
| 189 | +``` |
| 190 | +Order of processing: |
| 191 | +- Visit `2`, push it to the stack. |
| 192 | +- Visit `1`, push it to the stack. |
| 193 | +- Visit `0`, push it to the stack. |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | +### **Main Function: `topologicalSort`** |
| 198 | + |
| 199 | +```cpp |
| 200 | +void topologicalSort(vector<vector<int>>& adj, int V) { |
| 201 | + stack<int> Stack; |
| 202 | + vector<bool> visited(V, false); |
| 203 | +``` |
| 204 | +
|
| 205 | +- **`stack<int> Stack;`**: |
| 206 | + - Declares a stack to store nodes in topological order. |
| 207 | +
|
| 208 | +- **`vector<bool> visited(V, false);`**: |
| 209 | + - Initializes a `visited` array with `false` for all nodes, indicating that no nodes have been visited yet. |
| 210 | +
|
| 211 | +
|
| 212 | +
|
| 213 | +```cpp |
| 214 | + for (int i = 0; i < V; i++) { |
| 215 | + if (!visited[i]) { |
| 216 | + topologicalSortUtil(i, adj, visited, Stack); |
| 217 | + } |
| 218 | + } |
| 219 | +``` |
| 220 | + |
| 221 | +- **`for (int i = 0; i < V; i++)`**: |
| 222 | + - Loops through all nodes. |
| 223 | + - **`if (!visited[i]) {...}`**: |
| 224 | + - For unvisited nodes, calls `topologicalSortUtil` to perform DFS. |
| 225 | + |
| 226 | +**Example**: |
| 227 | +For the graph: |
| 228 | +``` |
| 229 | +0 → [1] |
| 230 | +1 → [2] |
| 231 | +3 → [1, 2] |
| 232 | +``` |
| 233 | +- The loop starts with node `0`, calls `topologicalSortUtil` for `0`. |
| 234 | +- Next, it processes node `3`. |
| 235 | + |
| 236 | + |
| 237 | + |
| 238 | +```cpp |
| 239 | + while (!Stack.empty()) { |
| 240 | + cout << Stack.top() << " "; |
| 241 | + Stack.pop(); |
| 242 | + } |
| 243 | +} |
| 244 | +``` |
| 245 | + |
| 246 | +- **`while (!Stack.empty()) {...}`**: |
| 247 | + - Retrieves nodes from the stack one by one and prints them in topological order. |
| 248 | + - **`Stack.top()`**: |
| 249 | + - Returns the top element of the stack. |
| 250 | + - **`Stack.pop()`**: |
| 251 | + - Removes the top element from the stack. |
| 252 | + |
| 253 | +**Example**: |
| 254 | +For the graph: |
| 255 | +``` |
| 256 | +0 → [1] |
| 257 | +1 → [2] |
| 258 | +3 → [1, 2] |
| 259 | +``` |
| 260 | +Stack content after processing: |
| 261 | +``` |
| 262 | +3, 0, 1, 2 |
| 263 | +``` |
| 264 | +Output: |
| 265 | +``` |
| 266 | +3 0 1 2 |
| 267 | +``` |
| 268 | + |
| 269 | + |
| 270 | + |
| 271 | +### **Driver Code: `main`** |
| 272 | + |
| 273 | +```cpp |
| 274 | +int main() { |
| 275 | + int V = 4; |
| 276 | + vector<vector<int>> edges = {{0, 1}, {1, 2}, {3, 1}, {3, 2}}; |
| 277 | +``` |
| 278 | +
|
| 279 | +- **`int V = 4;`**: |
| 280 | + - Defines the number of nodes (vertices) in the graph. |
| 281 | +
|
| 282 | +- **`vector<vector<int>> edges = {...};`**: |
| 283 | + - Represents directed edges between nodes. |
| 284 | +
|
| 285 | +**Example**: |
| 286 | +Edges `{0, 1}, {1, 2}, {3, 1}, {3, 2}` mean: |
| 287 | +``` |
| 288 | +0 → 1 |
| 289 | +1 → 2 |
| 290 | +3 → 1, 2 |
| 291 | +``` |
| 292 | +
|
| 293 | +
|
| 294 | +
|
| 295 | +```cpp |
| 296 | + vector<vector<int>> adj(V); |
| 297 | + for (auto i : edges) { |
| 298 | + adj[i[0]].push_back(i[1]); |
| 299 | + } |
| 300 | +``` |
| 301 | + |
| 302 | +- **`vector<vector<int>> adj(V);`**: |
| 303 | + - Adjacency list representation of the graph. |
| 304 | + |
| 305 | +- **`for (auto i : edges) {...}`**: |
| 306 | + - Converts the list of edges into an adjacency list. |
| 307 | + |
| 308 | +**Example**: |
| 309 | +For edges `{0, 1}, {1, 2}, {3, 1}, {3, 2}`, adjacency list becomes: |
| 310 | +``` |
| 311 | +0 → [1] |
| 312 | +1 → [2] |
| 313 | +3 → [1, 2] |
| 314 | +``` |
| 315 | + |
| 316 | + |
| 317 | + |
| 318 | +```cpp |
| 319 | + cout << "Topological sorting of the graph: "; |
| 320 | + topologicalSort(adj, V); |
| 321 | + return 0; |
| 322 | +} |
| 323 | +``` |
| 324 | +
|
| 325 | +- **`cout << ...`**: |
| 326 | + - Prints the message before calling the `topologicalSort` function. |
| 327 | +
|
| 328 | +- **`topologicalSort(adj, V);`**: |
| 329 | + - Computes the topological order and prints it. |
| 330 | +
|
| 331 | +
|
| 332 | +
|
| 333 | +### **Example Execution** |
| 334 | +
|
| 335 | +#### Input: |
| 336 | +``` |
| 337 | +V = 4 |
| 338 | +Edges: {{0, 1}, {1, 2}, {3, 1}, {3, 2}} |
| 339 | +``` |
| 340 | +
|
| 341 | +#### Adjacency List: |
| 342 | +``` |
| 343 | +0 → [1] |
| 344 | +1 → [2] |
| 345 | +3 → [1, 2] |
| 346 | +``` |
| 347 | +
|
| 348 | +#### Steps: |
| 349 | +1. Start DFS from `0`: |
| 350 | + - Visit `0 → 1 → 2`. |
| 351 | + - Push `2`, then `1`, then `0` to the stack. |
| 352 | +2. Start DFS from `3`: |
| 353 | + - Visit `3 → 1 → 2` (already visited). |
| 354 | + - Push `3` to the stack. |
| 355 | +
|
| 356 | +#### Stack: |
| 357 | +``` |
| 358 | +Stack: [3, 0, 1, 2] |
| 359 | +``` |
| 360 | +
|
| 361 | +#### Output: |
| 362 | +``` |
| 363 | +Topological sorting of the graph: 3 0 1 2 |
| 364 | +``` |
| 365 | +
|
| 366 | +
|
| 367 | +
|
| 368 | +### **Time and Space Complexity** |
| 369 | +
|
| 370 | +1. **Time Complexity**: |
| 371 | + - Visiting all nodes: **O(V)**. |
| 372 | + - Traversing all edges: **O(E)**. |
| 373 | + - Total: **O(V + E)**. |
| 374 | +
|
| 375 | +2. **Space Complexity**: |
| 376 | + - Stack and visited array: **O(V)**. |
| 377 | + - Total: **O(V)**. |
0 commit comments