Topological sort
Order the vertices of a directed acyclic graph so every edge points forward: Kahn’s algorithm with in-degrees, the DFS method, cycle detection, and critical-path scheduling.
Kahn’s algorithm
Count each vertex’s in-degree: how many prerequisites it has. Put every vertex with in-degree 0 in a queue: they can start now. Take one from the queue and add it to the order. For each vertex that depended on it, subtract 1 from its in-degree; if that reaches 0, put it in the queue. When the queue is empty: if every vertex is in the order, done. Otherwise the leftovers are stuck in a cycle.
string[] tasks = { "Survey", "Excavate", "Footings", "Order steel", "Fabricate", "Columns", "Beams", "Deck", "Roof" };(string Before, string After)[] deps ={ ("Survey", "Excavate"), ("Excavate", "Footings"), ("Footings", "Columns"), ("Order steel", "Fabricate"), ("Fabricate", "Columns"), ("Fabricate", "Beams"), ("Columns", "Beams"), ("Beams", "Deck"), ("Deck", "Roof")}; var plan = TopoSort(tasks, deps);Console.WriteLine(plan is null ? "Cycle: no valid order" : string.Join(" → ", plan)); static List<string>? TopoSort(string[] nodes, (string Before, string After)[] edges){ var next = nodes.ToDictionary(n => n, _ => new List<string>()); var inDegree = nodes.ToDictionary(n => n, _ => 0); foreach (var (a, b) in edges) { next[a].Add(b); inDegree[b]++; } var ready = new Queue<string>(nodes.Where(n => inDegree[n] == 0)); var order = new List<string>(); while (ready.Count > 0) { var u = ready.Dequeue(); order.Add(u); foreach (var v in next[u]) if (--inDegree[v] == 0) ready.Enqueue(v); // its last prerequisite is done } return order.Count == nodes.Length ? order : null; // leftovers mean a cycle}Survey → Order steel → Excavate → Fabricate → Footings → Columns → Beams → Deck → Roof
PriorityQueue instead of a Queue gives a specific order among tasks that are ready at the same time (for example alphabetical, or by priority), at O(log V) extra per step.
The DFS method
var next = new Dictionary<string, string[]>{ ["Underwear"] = new[] { "Trousers" }, ["Socks"] = new[] { "Boots" }, ["Trousers"] = new[] { "Boots", "Belt" }, ["Shirt"] = new[] { "Belt" }, ["Belt"] = Array.Empty<string>(), ["Boots"] = Array.Empty<string>()}; var done = new HashSet<string>();var finished = new List<string>();foreach (var task in next.Keys) Visit(task);finished.Reverse();Console.WriteLine(string.Join(", ", finished)); void Visit(string u){ if (!done.Add(u)) return; foreach (var v in next[u]) Visit(v); finished.Add(u); // u finishes after everything that needs it}Shirt, Socks, Underwear, Trousers, Belt, Boots
Scheduling: the critical path
Show a hint
Show the solution
string[] tasks = { "Survey", "Excavate", "Footings", "Order steel", "Fabricate", "Columns", "Beams", "Deck", "Roof" };int[] days = { 2, 5, 4, 10, 6, 3, 4, 3, 2 };(string Before, string After)[] deps ={ ("Survey", "Excavate"), ("Excavate", "Footings"), ("Footings", "Columns"), ("Order steel", "Fabricate"), ("Fabricate", "Columns"), ("Fabricate", "Beams"), ("Columns", "Beams"), ("Beams", "Deck"), ("Deck", "Roof")}; var duration = tasks.Zip(days).ToDictionary(p => p.First, p => p.Second);var inDegree = tasks.ToDictionary(t => t, _ => 0);var next = tasks.ToDictionary(t => t, _ => new List<string>());foreach (var (a, b) in deps) { next[a].Add(b); inDegree[b]++; } var finish = tasks.ToDictionary(t => t, _ => 0);var start = tasks.ToDictionary(t => t, _ => 0); // earliest startvar ready = new Queue<string>(tasks.Where(t => inDegree[t] == 0));while (ready.Count > 0){ var u = ready.Dequeue(); finish[u] = start[u] + duration[u]; foreach (var v in next[u]) { start[v] = Math.Max(start[v], finish[u]); // wait for the latest prerequisite if (--inDegree[v] == 0) ready.Enqueue(v); }} Console.WriteLine($"Project: {finish.Values.Max()} days");Console.WriteLine($"Columns can start on day {start["Columns"]}");Project: 28 days Columns can start on day 16
Remember
A topological order puts every task after its prerequisites; it exists only for DAGs. Kahn’s algorithm repeatedly takes tasks with in-degree 0: O(V + E). Leftovers mean a cycle. Reversed DFS finish order is also a topological order. With durations, processing in topological order gives earliest starts and the critical path.