package net.sourceforge.mayfly.graph; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; /** * @internal * This is basically a topological sort class. It is relatively general * but does have one assumption baked in: that one can order the nodes * (with no two being equal), and that one desires to use this order * to decide which nodes to select. */ public class Graph { SortedMap/*<Node,SortedSet<Node>>*/ predecessors = new TreeMap(new NodeComparator()); SortedMap/*<Node,SortedSet<Node>>*/ successors = new TreeMap(new NodeComparator()); public int nodeCount() { int count = predecessors.size(); if (count != successors.size()) { throw new RuntimeException( "have " + count + " predecessors but " + successors.size() + " successors"); } return count; } public void addNode(Node node) { Object oldPredecessors = predecessors.put(node, new TreeSet(new NodeComparator())); if (oldPredecessors != null) { throw new RuntimeException("already have node " + node); } successors.put(node, new TreeSet(new NodeComparator())); } public void addEdge(Node from, Node to) { ((SortedSet) predecessors.get(to)).add(from); ((SortedSet) successors.get(from)).add(to); } public SortedSet predecessors(Node to) { return (SortedSet) predecessors.get(to); } public SortedSet successors(Node from) { return (SortedSet) successors.get(from); } static class NodeComparator implements Comparator { public int compare(Object arg0, Object arg1) { Node first = (Node) arg0; Node second = (Node) arg1; return first.backupOrdering(second); } } public void removeEdge(Node from, Node to) { { boolean wasPresent = ((SortedSet) predecessors.get(to)).remove(from); if (!wasPresent) { throw new RuntimeException( "there was no edge from " + from + " to " + to); } } { boolean wasPresent = ((SortedSet) successors.get(from)).remove(to); if (!wasPresent) { throw new RuntimeException( "there was no edge from " + from + " to " + to); } } } public SortedSet nodesWithNoPredecessor() { SortedSet result = new TreeSet(new NodeComparator()); for (Iterator iter = predecessors.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); Node node = (Node) entry.getKey(); SortedSet predecessors = (SortedSet) entry.getValue(); if (predecessors.isEmpty()) { result.add(node); } } return result; } /** * This operation destroys the graph that it is operating on. */ public List topologicalSort() { List result = new ArrayList(); List queue = new ArrayList(nodesWithNoPredecessor()); int nodeCount = nodeCount(); while (result.size() < nodeCount) { sortStep(result, queue); } return result; } void sortStep(List result, List queue) { if (queue.isEmpty()) { throw new CycleDetectedException(); } Node head = (Node) queue.remove(0); result.add(head); SortedSet headSuccessors = new TreeSet(new NodeComparator()); headSuccessors.addAll(successors(head)); Iterator iterator = headSuccessors.iterator(); while (iterator.hasNext()) { Node next = (Node) iterator.next(); removeEdge(head, next); if (predecessors(next).size() == 0) { queue.add(next); } } } public void addNodes(List nodes) { for (Iterator iter = nodes.iterator(); iter.hasNext();) { Node table = (Node) iter.next(); addNode(table); } } }