// File: Graph.java from the package EDU.colorado.graphs
// Complete documentation is available from the Graph link in
// http://www.cs.colorado.edu/~main/docs/
package edu.colorado.graphs;
/******************************************************************************
* A Graph
is a labeled graph with a fixed number of vertices.
*
* Java Source Code for this class:
*
* http://www.cs.colorado.edu/~main/EDU/colorado/collections/Graph.java
*
*
* @author Michael Main
* (main@colorado.edu)
*
* @version Feb 10, 2016
******************************************************************************/
public class Graph implements Cloneable
{
// Invariant of the Graph class:
// 1. The vertex numbers range from 0 to labels.length-1.
// 2. For each vertex number i, labels[i] contains the label for vertex i.
// 3. For any two vertices i and j, edges[i][j] is true if there is a
// vertex from i to j; otherwise edges[i][j] is false.
private boolean[ ][ ] edges;
private Object[ ] labels;
/**
* Initialize a Graph
with n
vertices,
* no edges, and null labels.
* @param n
* the number of vertices for this Graph
* Precondition:
* n
is nonnegative.
* Postcondition:
* This Graph
has n
vertices, numbered
* 0
to n-1
. It has no edges and all
* vertex labels are null.
* @exception OutOfMemoryError
* Indicates insufficient memory for the specified number of nodes.
* @exception NegativeArraySizeException
* Indicates that n
is negative.
**/
public Graph(int n)
{
edges = new boolean[n][n]; // All values initially false
labels = new Object[n]; // All values initially null
}
/**
* Add a new edge to this Graph
.
* @param source
* the vertex number of the source of the new edge
* @param target
* the vertex number of the target of the new edge
* Precondition:
* Both source
and target
are nonnegative and
* less than size()
.
* Postcondition:
* This Graph
has all the edges that it originally had plus
* another edge from the specified source
to the specified
* target
. (If the edge was already present, then this
* Graph
is unchanged.)
* @exception ArrayIndexOutOfBoundsException
* Indicates that the source
or target
was not a
* valid vertex number.
**/
public void addEdge(int source, int target)
{
edges[source][target] = true;
}
/**
* Generate a copy of this Graph
.
* @return
* The return value is a copy of this Graph
. Subsequent changes to the
* copy will not affect the original, nor vice versa. Note that the return
* value must be type cast to a Graph
before it can be used.
* @throws OutOfMemoryError
* Indicates insufficient memory for creating the clone.
**/
public Object clone( )
{ // Clone a Graph object.
Graph answer;
try
{
answer = (Graph) super.clone( );
}
catch (CloneNotSupportedException e)
{ // This would indicate an internal error in the Java runtime system
// because super.clone always works for an Object.
throw new InternalError(e.toString( ));
}
answer.edges = (boolean [ ][ ]) edges.clone( );
answer.labels = (Object [ ]) labels.clone( );
return answer;
}
/**
* Static method to print the labels of a graph with a depth-first search.
* @param g
* a nonnull Graph
* @param start
* a vertex number from the Graph g
* Precondition:
* start
is nonnegative and less than g.size()
.
* Postcondition:
* A depth-first search of g
has been conducted, starting at
* the specified start vertex. Each vertex visited has its label printed
* using System.out.println
. Note that vertices that are not
* connected to the start will not be visited.
* @throws NullPointerException
* Indicates that g
is null.
* @throws ArrayIndexOutOfBoundsException
* Indicates that the vertex was not a valid vertex number.
* @throws OutOfMemoryError
* Indicates that there is insufficient memory for an array of boolean values
* used by this method.
**/
public static void depthFirstPrint(Graph g, int start)
{
boolean[ ] marked = new boolean [g.size( )];
depthFirstRecurse(g, start, marked);
}
/**
* Recursive method to carry out the work of depthFirstPrint
.
* @param g
* a nonnull Graph
* @param v
* a vertex number from the Graph g
* @param marked
* an array to indicate which vertices of g
have already
* been visited
* Precondition:
* v
is nonnegative and less than g.size()
.
* marked.length
is equal to g.size()
;
* for each vertex x
of g
, marked[x]
* is true
if x
has already been visited by this
* search; otherwise marked[x]
is false
.
* The vertex v
is an unmarked vertex that the search has
* just arrived at.
* Postcondition:
* The depth-first search of g
has been continued through
* vertex v
and beyond to all vertices that can be reached
* from v
via a path of unmarked vertices. Each vertex visited
* has its label printed using System.out.println.
* @throws NullPointerException
* Indicates that g
is null.
* @throws ArrayIndexOutOfBoundsException
* Indicates that the vertex was not a valid vertex number, or
* marked
was the wrong size.
**/
public static void depthFirstRecurse(Graph g, int v, boolean[ ] marked)
{
int[ ] connections = g.neighbors(v);
int i;
int nextNeighbor;
marked[v] = true;
System.out.println(g.getLabel(v));
// Traverse all the neighbors, looking for unmarked vertices:
for (i = 0; i < connections.length; i++)
{
nextNeighbor = connections[i];
if (!marked[nextNeighbor])
depthFirstRecurse(g, nextNeighbor, marked);
}
}
/**
* Accessor method to get the label of a vertex of this Graph
.
* @param vertex
* a vertex number
* Precondition:
* vertex
is nonnegative and
* less than size()
.
* @return
* the label of the specified vertex in this Graph
* @exception ArrayIndexOutOfBoundsException
* Indicates that the vertex
was not a
* valid vertex number.
**/
public Object getLabel(int vertex)
{
return labels[vertex];
}
/**
* Accessor method to determine whether this Graph
contains
* a specified edge.
* @param source
* the vertex number of the source of the specified edge
* @param target
* the vertex number of the target of the specified edge
* Precondition:
* Both source
and target
are nonnegative and
* less than size()
.
* @return
* The return value is true if this Graph
has an edge from the
* specified source
to the specified target
.
* Otherwise the return value is false.
* @exception ArrayIndexOutOfBoundsException
* Indicates that the source
or target
was not a
* valid vertex number.
**/
public boolean isEdge(int source, int target)
{
return edges[source][target];
}
/**
* Accessor method to obtain a list of neighbors of a specified vertex of
* this Graph
* @param vertex
* a vertex number
* Precondition:
* The value of source
is nonnegative and
* less than size()
.
* Precondition:
* vertex
is nonnegative and
* less than size()
.
* @return
* The return value is an array that contains all the vertex numbers of
* vertices that are targets for edges with a source at the specified
* vertex
.
* @exception ArrayIndexOutOfBoundsException
* Indicates that the source
or target
was not a
* valid vertex number.
**/
public int[ ] neighbors(int vertex)
{
int i;
int count;
int[ ] answer;
// First count how many edges have the vertex as their source
count = 0;
for (i = 0; i < labels.length; i++)
{
if (edges[vertex][i])
count++;
}
// Allocate the array for the answer
answer = new int[count];
// Fill the array for the answer
count = 0;
for (i = 0; i < labels.length; i++)
{
if (edges[vertex][i])
answer[count++] = i;
}
return answer;
}
/**
* Remove an edge from this Graph
.
* @param source
* the vertex number of the source of the removed edge
* @param target
* the vertex number of the target of the removed edge
* Precondition:
* Both source
and target
are nonnegative and
* less than size()
.
* Postcondition:
* This Graph
has all the edges that it originally had minus
* the edge from the specified source
to the specified
* target
. (If the edge was not present, then this
* Graph
is unchanged.)
* @exception ArrayIndexOutOfBoundsException
* Indicates that the source
or target
was not a
* valid vertex number.
**/
public void removeEdge(int source, int target)
{
edges[source][target] = false;
}
/**
* Modification method to change the label of a vertex of this Graph
.
* @param vertex
* a vertex number
* @param newLabel
* a new label (which may be null)
* Precondition:
* vertex
is nonnegative and
* less than size()
.
* Postcondition:
* The label of the specified vertex in this Graph
has been
* changed to the newLabel
.
* @exception IndexOutOfBoundsException
* Indicates that the vertex
was not a
* valid vertex number.
**/
public void setLabel(int vertex, Object newLabel)
{
labels[vertex] = newLabel;
}
/**
* Determine the number of vertices in this Graph
.
* @return
* the number of vertices in this Graph
**/
public int size( )
{
return labels.length;
}
}