| 9 | * @see https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm |
| 10 | */ |
| 11 | export const tarjan = (graph: number[][]): number[][] => { |
| 12 | if (graph.length === 0) { |
| 13 | return [] |
| 14 | } |
| 15 | |
| 16 | let index = 0 |
| 17 | // The order in which we discover nodes |
| 18 | const discovery: number[] = Array(graph.length) |
| 19 | // For each node, holds the furthest ancestor it can reach |
| 20 | const low: number[] = Array(graph.length).fill(undefined) |
| 21 | // Holds the nodes we have visited in a DFS traversal and are considering to group into a SCC |
| 22 | const stack: number[] = [] |
| 23 | // Holds the elements in the stack. |
| 24 | const stackContains = Array(graph.length).fill(false) |
| 25 | const sccs: number[][] = [] |
| 26 | |
| 27 | const dfs = (node: number) => { |
| 28 | discovery[node] = index |
| 29 | low[node] = index |
| 30 | ++index |
| 31 | stack.push(node) |
| 32 | stackContains[node] = true |
| 33 | |
| 34 | for (const child of graph[node]) { |
| 35 | if (low[child] === undefined) { |
| 36 | dfs(child) |
| 37 | if (low[child] < low[node]) { |
| 38 | // Child node loops back to this node's ancestor. Update the low node. |
| 39 | low[node] = low[child] |
| 40 | } |
| 41 | } else if (stackContains[child] && low[node] > discovery[child]) { |
| 42 | // Found a backedge. Update the low for this node if needed. |
| 43 | low[node] = discovery[child] |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | if (discovery[node] == low[node]) { |
| 48 | // node is the root of a SCC. Gather the SCC's nodes from the stack. |
| 49 | const scc: number[] = [] |
| 50 | let i |
| 51 | for (i = stack.length - 1; stack[i] != node; --i) { |
| 52 | scc.push(stack[i]) |
| 53 | stackContains[stack[i]] = false |
| 54 | stack.pop() |
| 55 | } |
| 56 | scc.push(stack[i]) |
| 57 | stackContains[stack[i]] = false |
| 58 | stack.pop() |
| 59 | sccs.push(scc) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | for (let i = 0; i < graph.length; ++i) { |
| 64 | if (low[i] === undefined) { |
| 65 | dfs(i) |
| 66 | } |
| 67 | } |
| 68 | return sccs |