-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathtarjan.ts
More file actions
50 lines (44 loc) · 1.24 KB
/
tarjan.ts
File metadata and controls
50 lines (44 loc) · 1.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import type { CodeGraph } from '../model.js';
/**
* Tarjan's strongly connected components algorithm.
* Operates on a CodeGraph instance.
*
* @returns SCCs with length > 1 (cycles)
*/
export function tarjan(graph: CodeGraph): string[][] {
let index = 0;
const stack: string[] = [];
const onStack = new Set<string>();
const indices = new Map<string, number>();
const lowlinks = new Map<string, number>();
const sccs: string[][] = [];
function strongconnect(v: string): void {
indices.set(v, index);
lowlinks.set(v, index);
index++;
stack.push(v);
onStack.add(v);
for (const w of graph.successors(v)) {
if (!indices.has(w)) {
strongconnect(w);
lowlinks.set(v, Math.min(lowlinks.get(v)!, lowlinks.get(w)!));
} else if (onStack.has(w)) {
lowlinks.set(v, Math.min(lowlinks.get(v)!, indices.get(w)!));
}
}
if (lowlinks.get(v) === indices.get(v)) {
const scc: string[] = [];
let w: string | undefined;
do {
w = stack.pop()!;
onStack.delete(w);
scc.push(w);
} while (w !== v);
if (scc.length > 1) sccs.push(scc);
}
}
for (const id of graph.nodeIds()) {
if (!indices.has(id)) strongconnect(id);
}
return sccs;
}