blob: c3e8ee12417aa505b054c163c5c2aab383e75d93 [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.libg.tarjan;
2
3import static java.lang.Math.*;
4
5import java.util.*;
6
7public class Tarjan<T> {
8
9 public class Node {
10 final T name;
11 final List<Node> adjacent = new ArrayList<Node>();
12 int low = -1;
13 int index = -1;
14
15 public Node(T name) {
16 this.name = name;
17 }
Stuart McCulloch2286f232012-06-15 13:27:53 +000018
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +000019 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +000020 public String toString() {
21 return name + "{" + index + "," + low + "}";
22 }
23 }
24
Stuart McCulloch2286f232012-06-15 13:27:53 +000025 private int index = 0;
26 private List<Node> stack = new ArrayList<Node>();
Stuart McCullochbb014372012-06-07 21:57:32 +000027 private Set<Set<T>> scc = new HashSet<Set<T>>();
Stuart McCulloch2286f232012-06-15 13:27:53 +000028 private Node root = new Node(null);
Stuart McCullochbb014372012-06-07 21:57:32 +000029
Stuart McCulloch2286f232012-06-15 13:27:53 +000030 // public ArrayList<ArrayList<Node>> tarjan(Node v, AdjacencyList list){
31 // v.index = index;
32 // v.lowlink = index;
33 // index++;
34 // stack.add(0, v);
35 // for(Edge e : list.getAdjacent(v)){
36 // Node n = e.to;
37 // if(n.index == -1){
38 // tarjan(n, list);
39 // v.lowlink = Math.min(v.lowlink, n.lowlink);
40 // }else if(stack.contains(n)){
41 // v.lowlink = Math.min(v.lowlink, n.index);
42 // }
43 // }
44 // if(v.lowlink == v.index){
45 // Node n;
46 // ArrayList<Node> component = new ArrayList<Node>();
47 // do{
48 // n = stack.remove(0);
49 // component.add(n);
50 // }while(n != v);
51 // SCC.add(component);
52 // }
53 // return SCC;
54 // }
Stuart McCullochbb014372012-06-07 21:57:32 +000055
56 void tarjan(Node v) {
57 v.index = index;
58 v.low = index;
59 index++;
60 stack.add(0, v);
61 for (Node n : v.adjacent) {
62 if (n.index == -1) {
63 // first time visit
64 tarjan(n);
65 v.low = min(v.low, n.low);
66 } else if (stack.contains(n)) {
67 v.low = min(v.low, n.index);
68 }
69 }
70
Stuart McCulloch2286f232012-06-15 13:27:53 +000071 if (v != root && v.low == v.index) {
Stuart McCullochbb014372012-06-07 21:57:32 +000072 Set<T> component = new HashSet<T>();
73 Node n;
74 do {
75 n = stack.remove(0);
76 component.add(n.name);
77 } while (n != v);
78 scc.add(component);
79 }
80 }
81
82 Set<Set<T>> getResult(Map<T, ? extends Collection<T>> graph) {
Stuart McCulloch2286f232012-06-15 13:27:53 +000083 Map<T,Node> index = new HashMap<T,Node>();
Stuart McCullochbb014372012-06-07 21:57:32 +000084
85 for (Map.Entry<T, ? extends Collection<T>> entry : graph.entrySet()) {
86 Node node = getNode(index, entry.getKey());
87 root.adjacent.add(node);
88 for (T adj : entry.getValue())
89 node.adjacent.add(getNode(index, adj));
90 }
91 tarjan(root);
92 return scc;
93 }
94
Stuart McCulloch2286f232012-06-15 13:27:53 +000095 private Node getNode(Map<T,Node> index, T key) {
Stuart McCullochbb014372012-06-07 21:57:32 +000096 Node node = index.get(key);
97 if (node == null) {
98 node = new Node(key);
99 index.put(key, node);
100 }
101 return node;
102 }
103
Stuart McCulloch2286f232012-06-15 13:27:53 +0000104 public static <T> Collection< ? extends Collection<T>> tarjan(Map<T, ? extends Collection<T>> graph) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000105 Tarjan<T> tarjan = new Tarjan<T>();
106 return tarjan.getResult(graph);
107 }
108}