/*********************************************************************************** * @author John Miller * @version 1.0 * @date Tue Feb 9 18:13:11 EST 2010 */ import scala.collection.mutable.Set /*********************************************************************************** * This class provides a means for building a precedence/directed graph and checking * it for cycles. For cycle detection, nodes are marked with traffic-light colors: * Green means go/unexplored, Yellow means caution/been there before, Red mean stop/ * already fully explored. */ class PrecedenceGraph (nNodes: Int) { /** Adjacency set representation of a directed graph */ private val graph = new Array [Set [Int]] (nNodes) /** Nodes are marked with traffic-light colors ('G'reen, 'Y'ellow, 'R'ed) */ private val color = new Array [Char] (nNodes) { for (i <- 0 until nNodes) { graph(i) = Set [Int] (); color(i) = 'G' } } // primary constructor /******************************************************************************* * Add an edge from node i to node j to the graph. * @param i the source node * @param j the target node */ def addEdge (i: Int, j: Int) { graph(i) += j } // addEdge /******************************************************************************* * Determine whether the graph contains a cycle. */ def hasCycle: Boolean = { for (i <- 0 until nNodes if color(i) == 'G' && loopback (i)) return true false } // hasCycle /******************************************************************************* * Search the decendents of node i to see if there is a loopback. * @param i the node where the search starts */ private def loopback (i: Int): Boolean = { if (color(i) == 'Y') return true color(i) = 'Y' for (j <- graph(i) if color(j) != 'R' && loopback (j)) return true color(i) = 'R' false } // loopback /******************************************************************************* * Convert the graph to a string. */ override def toString: String = { var s = "PrecedenceGraph ( " for (i <- 0 until nNodes) s += "< " + i + " --> " + graph(i) + " > " s + ")" } // toString } // PrecedenceGraph class /*********************************************************************************** * Test the PrecedenceGraph class. */ object PrecedenceGraphTest extends Application { val pg = new PrecedenceGraph (3) pg.addEdge (0, 1) pg.addEdge (0, 2) pg.addEdge (1, 2) pg.addEdge (2, 0) println ("pg = " + pg + "\nhas cycle = " + pg.hasCycle) } // PrecedenceGraphTest