index.js 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. "use strict";
  2. module.exports = tarjan;
  3. // Adapted from https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm#The_algorithm_in_pseudocode
  4. function tarjan(graph) {
  5. const indices = new Map();
  6. const lowlinks = new Map();
  7. const onStack = new Set();
  8. const stack = [];
  9. const scc = [];
  10. let idx = 0;
  11. function strongConnect(v) {
  12. indices.set(v, idx);
  13. lowlinks.set(v, idx);
  14. idx++;
  15. stack.push(v);
  16. onStack.add(v);
  17. const deps = graph.get(v);
  18. for (const dep of deps) {
  19. if (!indices.has(dep)) {
  20. strongConnect(dep);
  21. lowlinks.set(v, Math.min(lowlinks.get(v), lowlinks.get(dep)));
  22. } else if (onStack.has(dep)) {
  23. lowlinks.set(v, Math.min(lowlinks.get(v), indices.get(dep)));
  24. }
  25. }
  26. if (lowlinks.get(v) === indices.get(v)) {
  27. const vertices = new Set();
  28. let w = null;
  29. while (v !== w) {
  30. w = stack.pop();
  31. onStack.delete(w);
  32. vertices.add(w);
  33. }
  34. scc.push(vertices);
  35. }
  36. }
  37. for (const v of graph.keys()) {
  38. if (!indices.has(v)) {
  39. strongConnect(v);
  40. }
  41. }
  42. return scc;
  43. }