/* * Copyright 2014 WANdisco * * WANdisco licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package c5db.util; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; public class Graph { public static <E extends Comparable<E>> List<ImmutableList<Node<E>>> doTarjan(Collection<Node<E>> allNodes0) { List<Node<E>> allNodes = new ArrayList<>(allNodes0); Collections.sort(allNodes); resetIndexes(allNodes); int index = 0; Deque<Node<E>> s = new LinkedList<>(); List<ImmutableList<Node<E>>> components = new LinkedList<>(); for (Node<E> v : allNodes) { index = strongConnect(index, s, v, components); } return components; } private static <E extends Comparable<E>> int strongConnect(int index, Deque<Node<E>> s, Node<E> v, List<ImmutableList<Node<E>>> components) { if (v.index == -1) { v.index = index; v.lowlink = index; index += 1; s.push(v); for (Node<E> w : v.dependencies) { if (w.index == -1) { index = strongConnect(index, s, w, components); v.lowlink = Math.min(v.lowlink, w.lowlink); } else if (s.contains(w)) { v.lowlink = Math.min(v.lowlink, w.index); } } if (v.lowlink == v.index) { List<Node<E>> component = new LinkedList<>(); Node<E> w; do { w = s.pop(); component.add(w); } while (w != v); //System.out.println("Component: " + component); components.add(ImmutableList.copyOf(component)); } } return index; } private static <E extends Comparable<E>> void resetIndexes(Collection<Node<E>> values) { for (Node<E> n : values) { n.index = -1; n.lowlink = -1; } } public static class Node<E extends Comparable<E>> implements Comparable<Node<E>> { public final SortedSet<Node<E>> dependencies = new TreeSet<>(); public final E type; public int index = -1; public int lowlink = -1; public Node(E type) { this.type = type; } @Override public String toString() { return "Node{" + "type=" + type + ", dependencies=" + dependencies.size() + ", index,lowlink=" + index + "," + lowlink + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Node node = (Node) o; return type == node.type; } @Override public int compareTo(Node<E> o) { return type.compareTo(o.type); } } }