package graph; import java.util.Deque; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * This class represents directed and undirected graphs of vertices and * provides graph searching operations for them. * Graphs are internally represented using adjacency lists. * @author tcolburn */ public class Graph { /** * Constructs a new graph given lists of vertices and edges. * @param vertices A list of graph vertices * @param edges A list of graph edges * @param directed Whether the graph is directed or not */ public Graph(List<Vertex> vertices, List<Edge> edges, boolean directed) { this.vertices = vertices; this.directed = directed; adj_hash = new Hashtable<Vertex, List<Vertex>>(); Iterator<Vertex> vertexIterator = vertices.iterator(); while ( vertexIterator.hasNext() ) { Vertex v = (Vertex) vertexIterator.next(); adj_hash.put(v, new LinkedList<Vertex>()); } Iterator<Edge> iter = edges.iterator(); while (iter.hasNext()) { Edge e = iter.next(); addEdge(e.getV1(), e.getV2()); } searchStack = new Stack<Vertex>(); } /** * Adds an edge (v1, v2) to this graph. * If the graph is undirected, (v2, v1) is also added. * @param v1 The first vertex in the edge * @param v2 The second vertex in the edge */ private void addEdge(Vertex v1, Vertex v2) { adj_hash.get(v1).add(v2); if (!directed) { adj_hash.get(v2).add(v1); } } /** * Tests whether a pair of vertices forms an edge in this graph. * @param vertex1 The first vertex * @param vertex2 The second vertex * @return Whether there is an edge from the first vertex to the second */ public boolean isEdge(Vertex vertex1, Vertex vertex2) { return adj_hash.get(vertex1).contains(vertex2); } /** * Performs a breadth-first search of this graph from a given starting vertex. * For each vertex that is reachable from the start, this operation computes * its distance from the start and its predecessor on the search path. * @param start The start vertex */ public void breadthFirstSearch(Vertex start) { DequeAdder tailAdder = new DequeAdder() { public void add(Vertex vertex, Deque<Vertex> deque) { deque.addLast(vertex); } }; search(start, tailAdder); } /** * Performs a depth-first search of this graph from a given starting vertex. * For each vertex that is reachable from the start, this operation computes * its distance from the start and its predecessor on the search path. * @param start The start vertex */ public void depthFirstSearch(Vertex start) { DequeAdder headAdder = new DequeAdder() { public void add(Vertex vertex, Deque<Vertex> deque) { deque.addFirst(vertex); } }; search(start, headAdder); } /** * Produces a string representation of the search path from a start * vertex to an end vertex in this graph. * This method is intended to be called after subjecting the graph to * a search. * The string representation for an individual vertex is obtained * using its <b>toString</b> method. * @param start The start vertex in the search path * @param end The end vertex in the search path * @return A string representation of the search path */ public String pathString(Vertex start, Vertex end) { if ( start == end ) { return vertexString(start); } else if ( end.getPredecessor() == null ) { return ""; } else { return pathString(start, end.getPredecessor()) + vertexString(end); } } /** * A string representation of a vertex with end-of-lines before and after. * @param v A vertex * @return The vertex's string representation */ private String vertexString(Vertex v) { return "\n" + v.toString() + "\n"; } /** * The core search operation for this graph. * It uses a double-ended queue so that either breadth-first or * depth-first search can be performed depending on to which end of * the queue newly discovered vertices are added. * @param start The start vertex for the search * @param adder A purely functional object that adds to either the * head or tail of a double-ended queue */ private void search(Vertex start, DequeAdder adder) { searchInit(); start.setOpen(false); start.setDistance(0); Deque<Vertex> deque = new LinkedList<Vertex>(); deque.add(start); while ( !deque.isEmpty() ) { Vertex v = deque.remove(); List<Vertex> adjList = adj_hash.get(v); if ( adjList != null ) { Iterator iter = adjList.iterator(); while ( iter.hasNext() ) { Vertex successor = (Vertex) iter.next(); if ( successor.isOpen() ) { successor.setOpen(false); successor.setDistance(v.getDistance()+1); successor.setPredecessor(v); adder.add(successor, deque); } } } } } /** * An initializing operation for the core search operation. * All vertices are set to open with null predecessors and * a distance of inifinity from the start. */ private void searchInit() { Iterator<Vertex> iterator = vertices.iterator(); while ( iterator.hasNext() ) { Vertex vertex = (Vertex) iterator.next(); vertex.setOpen(true); vertex.setDistance(INFINITY); vertex.setPredecessor(null); } } /** * Accessor for a list of vertices making up this graph. * @return A list of vertices */ public List<Vertex> getVertices() { return vertices; } /** * Creates a string representation of this graph's adjacency list for testing. * @return The string representation of the adjacency list */ public String toString() { StringBuffer buffer = new StringBuffer(); Iterator vertexIterator = vertices.iterator(); while ( vertexIterator.hasNext() ) { Vertex vertex = (Vertex) vertexIterator.next(); buffer.append("\n" + vertex.getName()); List<Vertex> adjList = adj_hash.get(vertex); if ( adjList == null ) continue; Iterator listIterator = adjList.iterator(); while ( listIterator.hasNext() ) { Vertex adjVertex = (Vertex) listIterator.next(); buffer.append(" -> " + adjVertex.getName()); } } return buffer.toString(); } /** * Whether this graph is directed or not. */ private boolean directed; /** * The vertex's adjacency lists are stored in a hash table whose * keys are vertices and whose values are lists of vertices. */ private Hashtable<Vertex, List<Vertex>> adj_hash; /** * A list of vertices in this graph. This list is necessary because a * vertex may not get into the hash table if there is no edge from it. */ private List<Vertex> vertices; /** * A large number used to represent infinity for the search operations. * It is public just so test classes can use it. */ public static final int INFINITY = 999999999; }