☍ Topological Sorting – Complete In-Depth Explanation
Topological sorting is a linear ordering of vertices in a directed acyclic graph (DAG) such that for every directed edge (u, v), vertex u comes before vertex v in the ordering. It's like determining the order in which tasks must be performed given their dependencies.
📌 Why is Topological Sorting Important?
- 💡 Task Scheduling: Determining the order of tasks based on dependencies.
- ⚙️ Dependency Resolution: Resolving dependencies in software projects.
- 🚀 Course Scheduling: Ordering courses based on prerequisites.
📌 Understanding Topological Sorting with an Example
Consider the following DAG representing course prerequisites:
A --> B
| ^
v |
C --> D
| ^
v |
E --> F
A topological sort of this graph would give a valid order in which the courses can be taken, respecting the prerequisites. One possible topological order is: A, C, E, B, D, F. (There can be multiple valid topological orderings.)
🔹 Key Points
- Only applicable to directed acyclic graphs (DAGs).
- Multiple topological orderings may exist.
- Represents a valid sequence of tasks respecting dependencies.
🛠 Solution Approaches
There are two main approaches to topological sorting:
📌 1. Depth-First Search (DFS)
- Perform DFS on the graph.
- During the backtracking phase of DFS (after visiting all descendants of a vertex), push the vertex onto a stack.
- Reverse the stack to get the topological order.
📌 2. Kahn's Algorithm (using indegree)
- Calculate the indegree (number of incoming edges) of each vertex.
- Add vertices with indegree 0 to a queue.
- While the queue is not empty:
- Dequeue a vertex u.
- For each neighbor v of u:
- Decrement indegree of v.
- If indegree of v becomes 0, enqueue v.
#include
#include
#include
#include
using namespace std;
// DFS-based topological sort
void dfs(int v, vector>& adj, vector& visited, stack& st) {
visited[v] = true;
for (int u : adj[v]) {
if (!visited[u]) {
dfs(u, adj, visited, st);
}
}
st.push(v);
}
vector topologicalSortDFS(int n, vector>& adj) {
vector visited(n, false);
stack st;
for (int v = 0; v < n; v++) {
if (!visited[v]) {
dfs(v, adj, visited, st);
}
}
vector result;
while (!st.empty()) {
result.push_back(st.top());
st.pop();
}
return result;
}
// Kahn's algorithm
vector topologicalSortKahn(int n, vector>& adj) {
vector indegree(n, 0);
for (int v = 0; v < n; v++) {
for (int u : adj[v]) {
indegree[u]++;
}
}
queue q;
for (int v = 0; v < n; v++) {
if (indegree[v] == 0) {
q.push(v);
}
}
vector result;
while (!q.empty()) {
int u = q.front();
q.pop();
result.push_back(u);
for (int v : adj[u]) {
indegree[v]--;
if (indegree[v] == 0) {
q.push(v);
}
}
}
return result;
}
int main() {
int n = 6; // Number of vertices
vector> adj(n);
// Example graph (replace with your graph)
adj[0].push_back(1);
adj[0].push_back(2);
adj[2].push_back(3);
adj[1].push_back(3);
adj[2].push_back(4);
adj[4].push_back(5);
cout << "Topological Sort (DFS): ";
vector sortedDFS = topologicalSortDFS(n, adj);
for (int v : sortedDFS) cout << v << " ";
cout << endl;
cout << "Topological Sort (Kahn's): ";
vector sortedKahn = topologicalSortKahn(n, adj);
for (int v : sortedKahn) cout << v << " ";
cout << endl;
return 0;
}
⏳ Time Complexity Analysis
Both DFS-based and Kahn's algorithm have a time complexity of O(V + E), where V is the number of vertices and E is the number of edges.
🌍 Real-World Applications of Topological Sorting
- 🏗️ Project management (task scheduling).
- 💻 Compilers (dependency resolution).
- 📚 Course scheduling.