Depth-first search
Explore as deep as possible before backing up, recursively or with a stack, and use DFS to find connected components, detect cycles and reason about dependencies.
Recursive DFS
var adj = new Dictionary<char, char[]>{ ['A'] = new[] { 'B', 'D' }, ['B'] = new[] { 'A', 'C', 'E' }, ['C'] = new[] { 'B', 'E', 'F' }, ['D'] = new[] { 'A', 'E', 'G' }, ['E'] = new[] { 'B', 'C', 'D', 'F', 'G' }, ['F'] = new[] { 'C', 'E', 'G' }, ['G'] = new[] { 'D', 'E', 'F' }}; var visited = new HashSet<char>();var order = new List<char>();Visit('A');Console.WriteLine(string.Join(" ", order)); void Visit(char u){ visited.Add(u); order.Add(u); foreach (char v in adj[u]) if (!visited.Contains(v)) Visit(v); // go deeper; when it returns, we are back at u}A B C E D G F
Iterative DFS with a stack
Stack<T> and you get a depth-first order without recursion:
var adj = new Dictionary<char, char[]>{ ['A'] = new[] { 'B', 'D' }, ['B'] = new[] { 'A', 'C', 'E' }, ['C'] = new[] { 'B', 'E', 'F' }, ['D'] = new[] { 'A', 'E', 'G' }, ['E'] = new[] { 'B', 'C', 'D', 'F', 'G' }, ['F'] = new[] { 'C', 'E', 'G' }, ['G'] = new[] { 'D', 'E', 'F' }}; var visited = new HashSet<char>();var order = new List<char>();var stack = new Stack<char>();stack.Push('A');while (stack.Count > 0){ char u = stack.Pop(); if (!visited.Add(u)) continue; // already visited via another route order.Add(u); foreach (char v in adj[u].Reverse()) // reversed, so the first neighbour is popped first if (!visited.Contains(v)) stack.Push(v);}Console.WriteLine(string.Join(" ", order));A B C E D G F
Connected components
int n = 8;int[][] links = { new[] { 0, 1 }, new[] { 1, 2 }, new[] { 3, 4 }, new[] { 5, 6 }, new[] { 6, 7 }, new[] { 5, 7 } }; var adj = new List<int>[n];for (int i = 0; i < n; i++) adj[i] = new List<int>();foreach (var e in links) { adj[e[0]].Add(e[1]); adj[e[1]].Add(e[0]); } var group = new int[n];Array.Fill(group, -1);int groups = 0;for (int s = 0; s < n; s++){ if (group[s] != -1) continue; Mark(s, groups++); // a new component starts here}Console.WriteLine($"{groups} components: {string.Join(" ", group)}"); void Mark(int u, int id){ group[u] = id; foreach (int v in adj[u]) if (group[v] == -1) Mark(v, id);}3 components: 0 0 0 1 1 2 2 2
Finding cycles in dependencies
var deps = new Dictionary<string, string[]>{ ["Excavate"] = new[] { "Footings" }, ["Footings"] = new[] { "Columns" }, ["Columns"] = new[] { "Beams" }, ["Beams"] = new[] { "Deck" }, ["Deck"] = new[] { "Roof" }, ["Roof"] = Array.Empty<string>()};Console.WriteLine(HasCycle(deps)); deps["Roof"] = new[] { "Excavate" }; // a wrong dependencyConsole.WriteLine(HasCycle(deps)); static bool HasCycle(Dictionary<string, string[]> g){ var state = new Dictionary<string, int>(); // missing = new, 1 = on the current path, 2 = finished foreach (var node in g.Keys) if (Visit(node)) return true; return false; bool Visit(string u) { int s = state.GetValueOrDefault(u); if (s == 1) return true; // back on the current path: a cycle if (s == 2) return false; // already fully explored state[u] = 1; foreach (var v in g[u]) if (Visit(v)) return true; state[u] = 2; // leaving u: no longer on the path return false; }}False True
BFS or DFS?
| Need | Use |
|---|---|
CountComponents(int n, int[][] links) using DFS with an explicit Stack<int> (no recursion). For n = 7 and links (0,1), (1,2), (3,4), (5,5) the answer is 4: {0,1,2}, {3,4}, {5} and {6}.
Show a hint
Show the solution
Console.WriteLine(CountComponents(7, new[] { new[] { 0, 1 }, new[] { 1, 2 }, new[] { 3, 4 }, new[] { 5, 5 } })); static int CountComponents(int n, int[][] links){ var adj = new List<int>[n]; for (int i = 0; i < n; i++) adj[i] = new List<int>(); foreach (var e in links) { adj[e[0]].Add(e[1]); adj[e[1]].Add(e[0]); } var seen = new bool[n]; int count = 0; for (int s = 0; s < n; s++) { if (seen[s]) continue; count++; var stack = new Stack<int>(); stack.Push(s); seen[s] = true; while (stack.Count > 0) { int u = stack.Pop(); foreach (int v in adj[u]) if (!seen[v]) { seen[v] = true; stack.Push(v); } } } return count;}4
Remember
DFS goes as deep as possible, then backs up; recursion or an explicit stack, O(V + E). One DFS per unvisited vertex finds the connected components. In directed graphs, reaching a vertex still on the current path means a cycle. Use BFS for shortest steps; DFS for cycles, ordering, dependencies and backtracking.