Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 1 | package aQute.libg.tarjan; |
| 2 | |
| 3 | import static java.lang.Math.*; |
| 4 | |
| 5 | import java.util.*; |
| 6 | |
| 7 | public 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 McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 18 | |
Stuart McCulloch | 55d4dfe | 2012-08-07 10:57:21 +0000 | [diff] [blame] | 19 | @Override |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 20 | public String toString() { |
| 21 | return name + "{" + index + "," + low + "}"; |
| 22 | } |
| 23 | } |
| 24 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 25 | private int index = 0; |
| 26 | private List<Node> stack = new ArrayList<Node>(); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 27 | private Set<Set<T>> scc = new HashSet<Set<T>>(); |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 28 | private Node root = new Node(null); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 29 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 30 | // 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 McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 55 | |
| 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 McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 71 | if (v != root && v.low == v.index) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 72 | 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 McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 83 | Map<T,Node> index = new HashMap<T,Node>(); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 84 | |
| 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 McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 95 | private Node getNode(Map<T,Node> index, T key) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 96 | 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 McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 104 | public static <T> Collection< ? extends Collection<T>> tarjan(Map<T, ? extends Collection<T>> graph) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 105 | Tarjan<T> tarjan = new Tarjan<T>(); |
| 106 | return tarjan.getResult(graph); |
| 107 | } |
| 108 | } |