http://www.microsoft.com/college/
while not done if the graph is empty, then we're done (exit the loop) pick a node with no predecessors if no such node exists , then the graph is cyclic (exit the loop) output that node (number that node) delete that node from the graph end while
/**
* Output the nodes in the current acyclic directed graph so that
* when there is a path from A to B, A is output before B.
* pre: The graph is acyclic
* post: The graph may be modified
* post: All nodes in the graph are output
* post: The output order follows the dependencies of the graph.
*
* @exception CyclicException if the graph is cyclic.
*/
void topologicalSort() throws CyclicException {
// If the graph is empty, then we're done
if empty() return;
// Find a node with no predecessors
Node small = fewestPredecessors();
// If no such node exists, the graph is cyclic
if (small.predCount() != 0) {
throw new CyclicException("Can't toposort cyclic graphs");
}
// Output that node
System.out.print(small.contents());
// Delete it from the graph
delete(small);
// And go on
topologicalSort();
} // topologicalSort
delete() and
fewestPredecessors() n times, where n
is the number of nodes in the graph.
delete() is likely to take time proportional to the
number of edges incident to the deleted node.
fewestPredecessors() is likely to take O(n) time
in a graph structure not optimized for this operation.
delete()s will then be O(m),
where m is the number of edges in the graph.
fewestPredecessors() will then be
O(n^2).
fewestPredecessors()
take less time by using a heap, it turns out that this isn't as good
a solution as it might seem because we need to update the predecessor
count of a number of nodes each time we delete a node.
/** See description above. */
public void topologicalSort() {
// Variables
Dictionary adjacencies = new Dictionary();
// Adjacency lists
Dictionary pred_count = new Dictionary();
// Predecessor count of each node
Linear no_pred = new Linear();
// Nodes with no predecessors
Edge e; // The next edge to deal with
Object source; // Source of directed edge
Object sink; // Sink of directed edge
// Fill in the adjacency list
for(Enumeration edges = this.edges(); edges.hasMoreElements();) {
e = edges.nextElement();
source = e.source();
sink = e.sink();
// If the source or sink isn't in the dictionaries, add it
if (!adjacencies.contains(source)) {
adjacencies.put(source, new Linear());
pred_count.put(source, new Counter());
}
if (!adjacencies.contains(sink)) {
adjacencies.put(sink, new Linear());
pred_count.put(sink, new Counter());
}
// Update adjacency list for source
adjacencies.get(source).add(sink);
// Update predecessor count for sink (not real Java)
((Counter) pred_count.get(source)).increment();
} // for
// Identify all nodes with no predecessors
for(Enumeration nodes = pred_count.keys(); nodes.hasMoreElements(); ) {
source = nodes.nextElement();
if (((Counter) pred_count.get(source)).isZero()) {
no_pred.add(source);
}
} // for
// As long as there are nodes with no predecessors, output and
// "delete" them
while (!no_pred.empty()) {
source = no_pred.next();
source.output();
for (Enumeration neighbors = adjacencies.get(source);
neighbors.hasMoreElements(); ) {
sink = neighbors.nextElement();
((Counter) pred_count.get(sink)).decrement();
if ((Counter.pred_count.get(sink)).isZero()) {
no_pred.add(sink);
}
} // for
} // while
// Are there nodes remaining? If so, it was a cyclic graph.
for(Enumeration nodes = pred_count.keys(); nodes.hasMoreElements(); ) {
source = nodes.nextElement();
if (!pred_count.get(source).isZero()) {
throw new CyclicException();
}
} // for
} // topologicalSort()
Counter class that we can use
to count references. It should be trivial to implement that counter.
Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.
Source text last modified Fri Dec 5 08:25:45 1997.
This page generated on Fri Dec 5 09:43:12 1997 by SiteWeaver.
Contact our webmaster at rebelsky@math.grin.edu