// Stephanie's class notes. // sorely missing comments and docstrings. sorry. // Graph implemented with adjacency list // Note: I have implemented the graph as an undirected graph. import java.util.*; public class Graph1 { private ArrayList nodes; public enum Color { RED, BLUE, NONE }; public static class GraphNode { private ArrayList neighbors; String label; boolean marked; Color color; public GraphNode() { this.neighbors = new ArrayList(); this.label = ""; this.marked = false; this.color = Color.NONE; } public GraphNode(String label) { this.neighbors = new ArrayList(); this.label = label; this.marked = false; } // make a directed connection from this node to the other node public void connectTo( GraphNode other ) { this.neighbors.add( other ); } public String toString() { String ret = this.label + ":"; for (GraphNode n: this.neighbors) ret += " " + n.label; return ret; } } // end class GraphNode public Graph1() { nodes = new ArrayList(); } public void connect( GraphNode fromNode, GraphNode toNode ) { if (! this.nodes.contains( fromNode )) this.nodes.add( fromNode ); if (! this.nodes.contains( toNode )) this.nodes.add( toNode ); fromNode.connectTo( toNode ); toNode.connectTo( fromNode ); } public void printAll() { for (GraphNode n: nodes) System.out.println( n ); } public void generalTraversalPrint(GraphNode n0) { // unmark all nodes for (GraphNode n: nodes) n.marked = false; ArrayDeque nbs = new ArrayDeque(); nbs.add( n0 ); while (!nbs.isEmpty()) { GraphNode n = nbs.remove(); n.marked = true; System.out.println( n ); for (GraphNode p: n.neighbors) { if (!p.marked && !nbs.contains(p)) nbs.add( p ); } } } public boolean isConnected() { if (this.nodes.size() == 0) return false; //unmark all nodes for (GraphNode n: nodes) n.marked = false; ArrayDeque q = new ArrayDeque(); //choose a starting node and add it to q q.add( this.nodes.get(0) ); while (!q.isEmpty() ) { GraphNode n = q.remove(); n.marked = true; for (GraphNode p: n.neighbors) if (!p.marked && !q.contains(p)) { q.add(p); } } // look for any unvisited nodes for (GraphNode n: this.nodes) { if (!n.marked) { return false; } } return true; } private boolean thereAreUnmarkedNodes() { for (GraphNode n: nodes) if (!n.marked) return true; return false; } private GraphNode getFirstUnmarkedNode() { for (GraphNode n: nodes) if (!n.marked) return n; return null; } // returns true if the graph has cycles public boolean hasCycles() { if (this.nodes.size() == 0) return false; //unmark all nodes for (GraphNode n: nodes) n.marked = false; ArrayDeque q = new ArrayDeque(); while (thereAreUnmarkedNodes()) { // choose an unmarked starting node n and add n to C GraphNode n = getFirstUnmarkedNode(); q.add(n); // Check this connected component for a cycle while (!q.isEmpty()) { n = q.remove(); n.marked = true; int cnt = 0; for (GraphNode p: n.neighbors) { if (p.marked || q.contains(p)) cnt++; } // if n has two neighbors that are marked or in C: if (cnt >= 2) return true; for (GraphNode p: n.neighbors) { if (!p.marked && !q.contains(p)) q.add(p); } } } return false; } private boolean thereAreUncoloredNodes() { for (GraphNode n: nodes) if (n.color == Color.NONE) return true; return false; } private GraphNode getFirstUncoloredNode() { for (GraphNode n: nodes) if (n.color == Color.NONE) return n; return null; } // returns true if the graph is bipartite public boolean isTwoColorable() { // uncolor all nodes for (GraphNode n: this.nodes) n.color = Color.NONE; ArrayDeque q = new ArrayDeque(); while (thereAreUncoloredNodes()) { // choose an uncolored starting node n GraphNode n = getFirstUncoloredNode(); // color n blue and add n to C n.color = Color.BLUE; q.add( n ); while (!q.isEmpty()) { n = q.remove(); for (GraphNode p: n.neighbors) { if (p.color == Color.NONE) { // color p the opposite color of n if (n.color == Color.RED) p.color = Color.BLUE; else p.color = Color.RED; q.add(p); } else if (p.color == n.color) return false; } } } return true; } public static void main( String[] args ) { Graph1 g = new Graph1(); GraphNode n1 = new GraphNode( "n1" ); GraphNode n2 = new GraphNode( "n2" ); GraphNode n3 = new GraphNode( "n3" ); g.connect( n1, n2 ); g.connect( n3, n2 ); g.printAll(); System.out.println( "Traversing from n1" ); g.generalTraversalPrint( n1 ); System.out.println( "Traversing from n2" ); g.generalTraversalPrint( n2 ); System.out.println( "Traversing from n3" ); g.generalTraversalPrint( n3 ); System.out.println( "testing connected" ); System.out.println( "connected (should be true): " + g.isConnected() ); GraphNode n4 = new GraphNode( "n4" ); g.nodes.add( n4 ); System.out.println( "connected (should be false): " + g.isConnected() ); System.out.println( "testing 2-coloring" ); System.out.println( "2-colorable (should be true): " + g.isTwoColorable() ); // make it not bipartite g.connect( n3, n1 ); System.out.println( "2-colorable (should be false): " + g.isTwoColorable() ); } }