unm.cs351.f11.tdrl.p1
Interface Graph<T>


public interface Graph<T>

This Interface specifies a basic directed graph data structure in "adjacency list" representation. It supports operations such as adding nodes and arcs/edges, finding nodes and the neighbors of a node, etc. It does not support deletion of nodes, node or edge annotation, or edge weights.

Implementation of this type rely on the input objects' versions of Object.equals(Object) and Object.hashCode() to establish identity and comparison. Such implementations MUST NOT rely on any natural ordering among the nodes.

Version:
1.0
Author:
terran

Method Summary
 void addEdge(T from, T to)
          Insert a directed edge between two nodes.
 void addNode(T node)
          Insert a new node into this graph.
 boolean containsEdge(T from, T to)
          Test for the presence of a directed edge between two nodes.
 boolean containsNode(T node)
          Returns true iff the argument specifies a node in the graph.
 int edgeCount()
          Return a count of the total number of unique, directed edges in the graph.
 boolean equals(Object o)
          Every concrete class for the Graph interface MUST implement the equals() method, as specified by Object.equals(Object).
 Iterator<SearchState<T>> getBFSIterator(T node)
          Produce an iterator for a breadth-first search of the graph, starting at a fixed node.
 Iterator<SearchState<T>> getDFSIterator(T node)
          Produce an iterator for a depth-first search of the graph, starting at a fixed node.
 T getNodeByID(int nodeID)
          Return the node corresponding to the specified ID.
 int getNodeID(T node)
          Return a unique numeric ID code on the range [0,V-1] for the specified node.
 int hashCode()
          Every concrete instantiation of the Graph interface MUST implement the hashCode method, as specified by Object.hashCode().
 int neighborCount(T node)
          Get the number of neighbors of a target node.
 Set<T> neighborSet(T node)
          Returns an immutable set view of all of the neighbors of a fixed node in the graph.
 Set<T> nodeSet()
          Returns an immutable set view of all of the nodes in the graph.
 int size()
          Returns the number of nodes in this graph.
 

Method Detail

addNode

void addNode(T node)
Insert a new node into this graph. If the node already exists in the graph, then this method has no effect. A null argument generates a NullPointerException. If the node is already present in the graph, this method silently returns with no effect. (Specifically it MUST NOT either generate an exception or add a second copy of the node to the graph.)

This method MUST run in amortized O(1) time.

Parameters:
node - Node to add to graph.
Throws:
NullPointerException - iff node==null

containsNode

boolean containsNode(T node)
Returns true iff the argument specifies a node in the graph.

This method MUST run in O(1) time.

Parameters:
node - Node to test
Returns:
Whether or not node is currently part of the graph

nodeSet

Set<T> nodeSet()
Returns an immutable set view of all of the nodes in the graph. The returned Set object gives access to all of the elements in the underlying graph as if they were members of the set itself, though it MUST NOT create new copies of the nodes. It MUST support the full Set interface, including a correct Iterator method. The returned Set MUST be immutable. Specifically, the Set.add(Object), Set.remove(Object), etc. methods that would normally modify the state of the object MUST all throw UnsupportedOperationException if called. Further, the Iterator that the Set returns MUST also be immutable, as must any other derived objects.

Note that the Set object returned by this is free to, itself, represent an arbitrary order on nodes. That is, it is free to iterate over the nodes in any order it wishes, so long as it correctly enumerates the entire node set.

If the graph is currently empty, this still returns a Set, but that set is empty (nodeSet().size()==0).

This method MUST run in O(1) time. The returned Set view MUST use O(1) space and implement Set.contains(Object) in O(1) time. The Set.iterator() call MUST run in O(1) time. The returned Iterator object MUST require only O(1) space, MUST return each element in O(1) time, and MUST be capable of iterating over all n nodes of the graph in Theta(n) time.

Returns:
Immutable set view of the nodes of the graph.

size

int size()
Returns the number of nodes in this graph. NOTE This is only one possible measure of the "size" of a graph -- other measures include the number of edges (available via edgeCount()), diameter, maximum indegree/outdegree, etc.

Because multiple node additions are ignored (see addNode(Object), this is also unaffected by re-addition of a node.

This method MUST return in O(1) time.

Returns:
Number of nodes in this graph.

addEdge

void addEdge(T from,
             T to)
             throws GraphStructureException
Insert a directed edge between two nodes. This method assumes that both nodes already exist in the graph. If they don't, it throws a GraphStructureException to indicate a violation of this assumption. This method does allow self-edges (i.e., an edge from node X to node X).

Because this graph supports directed edges, addEdge(X,Y) is not the same as addEdge(Y,X), when !X.equals(Y).

An already-existing edge may be re-added, but this is silently ignored and does not change the data structure at all. (In particular, it does not change the total edge count.)

This method MUST run in amortized O(1) time and require only amortized O(1) space.

Parameters:
from - Parent/orgin of the edge
to - Child/destination of the edge
Throws:
GraphStructureException - if either of from or to are not present in the graph.

containsEdge

boolean containsEdge(T from,
                     T to)
Test for the presence of a directed edge between two nodes. true iff both from and to are nodes in the graph and they are connected by a directed edge that originates at from and terminates at to. (That is, containsEdge(X,Y)==true iff addEdge(X,Y) was successfully executed at some time in the past.

Note that this simply returns false if either from or to does not exist in this graph. It MUST NOT fail or throw an exception in this case.

This method MUST run in O(1) time and require O(1) new space allocation.

Parameters:
from - Parent node to test
to - Child node to test
Returns:
true iff nodes are connected

edgeCount

int edgeCount()
Return a count of the total number of unique, directed edges in the graph. This does count self-edges as edges.

Because multiple node additions are ignored (see addEdge(Object, Object), this is also unaffected by re-addition of an edge.

This method MUST run in O(1) time and require 0 new space allocation.

Returns:
Number of edges in graph.

neighborSet

Set<T> neighborSet(T node)
                   throws GraphStructureException
Returns an immutable set view of all of the neighbors of a fixed node in the graph. That is, if addEdge(X,Y) has successfully been executed some time in the past, then neighborSet(X).contains(Y)==true (otherwise, it is false).

The returned Set object gives access to all of the neighbor nodes of the query as if they were members of the set itself, though it MUST NOT create new copies of the nodes. It MUST support the full Set interface, including a correct Iterator method. The returned Set MUST be immutable. Specifically, the Set.add(Object), Set.remove(Object), etc. methods that would normally modify the state of the object MUST all throw UnsupportedOperationException if called. Further, the Iterator that the Set returns MUST also be immutable, as must any other derived objects.

If node is not a member of the graph (i.e., containsNode(Object) is false), then this throws a GraphStructureException to indicate a malformed query.

Note that the Set returned by this method is free to represent the neighbors of a node in any order it wishes.

If the queried node exists, but has no neighbors, this still returns a Set, but that Set is empty (i.e., neighborSet(X).size()==0).

This method MUST run in O(1) time. The returned Set view MUST use O(1) space and implement Set.contains(Object) in O(1) time. The Set.iterator() call MUST run in O(1) time. The returned Iterator object MUST require only O(1) space, MUST return each element in O(1) time, and MUST be capable of iterating over all n neighbor nodes in Theta(n) time.

Parameters:
node - Node whose neighbors should be queried.
Returns:
Immutable set view of the neighbors of node
Throws:
GraphStructureException - if node doesn't exist in this graph

neighborCount

int neighborCount(T node)
                  throws GraphStructureException
Get the number of neighbors of a target node.

If node is not a member of the graph (i.e., containsNode(Object) is false), then this throws a GraphStructureException to indicate a malformed query.

This method MUST run in O(1) time and require 0 additional space.

Parameters:
node - Target node to examine
Returns:
Number of nodes that are neighbor to node
Throws:
GraphStructureException - if node doesn't exist in this graph

getDFSIterator

Iterator<SearchState<T>> getDFSIterator(T node)
                                        throws GraphStructureException
Produce an iterator for a depth-first search of the graph, starting at a fixed node. This method produces an iterator that traverses a graph in a depth-first (i.e., preorder) order. The iterator MUST eventually return every reachable node of the graph, but it MUST NOT return any node more than once. Each call to Iterator.next() MUST run in amortized O(1) time. The iterator MAY use more than O(1) space to store its state, though it MUST NOT make a complete copy of the graph. In particular, it MAY use space up to O(size()) to store state, but it MUST NOT use as much as O(edgeCount().

The getDFSIterator(Object) method MUST return in O(1) time. Specifically, it MUST NOT copy or make explicit reference to all nodes or all edges of the graph.

Parameters:
node - Starting point for the traversal.
Returns:
Iterator for a depth-first search of the graph. Note that the returned iterator itself generates SearchState objects. These objects allow clients to retrieve not only the node of the current point of the iteration, but also the path by which the current node was generated in the search and the depth of the node in the search.
Throws:
GraphStructureException - If the starting node is not a legitimate node of the graph.

getBFSIterator

Iterator<SearchState<T>> getBFSIterator(T node)
                                        throws GraphStructureException
Produce an iterator for a breadth-first search of the graph, starting at a fixed node. This method produces an iterator that traverses a graph in a breadth-first order. The iterator MUST eventually return every reachable node of the graph, but it MUST NOT return any node more than once. Each call to Iterator.next() MUST run in amortized O(1) time. The iterator MAY use more than O(1) space to store its state, though it MUST NOT make a complete copy of the graph. In particular, it MAY use space up to O(size()) to store state, but it MUST NOT use as much as O(edgeCount().

The getBFSIterator(Object) method MUST return in O(1) time. Specifically, it MUST NOT copy or make explicit reference to all nodes or all edges of the graph.

Parameters:
node - Starting point for the traversal.
Returns:
Iterator for a breadth-first search of the graph. Note that the returned iterator itself generates SearchState objects. These objects allow clients to retrieve not only the node of the current point of the iteration, but also the path by which the current node was generated in the search and the depth of the node in the search. (For a breadth-first search in an unweighted graph, this is guaranteed to yield the shortest path to a node.)
Throws:
GraphStructureException - If the starting node is not a legitimate node of the graph.

equals

boolean equals(Object o)
Every concrete class for the Graph interface MUST implement the equals() method, as specified by Object.equals(Object). For graph objects, equality is defined to be:

Two graphs are equal iff they have the same node sets and same edge sets. Specifically:

This method MUST NOT generate any exceptions. If one of the two graphs does not contain some node/edge that exists in the other, then this MUST return false. This MUST also return false, rather than throwing an exception, when o is not a Graph object.

This method MUST run in O(V+E) time, where V is the number of nodes (vertices) in either graph and E is the number of edges.

Overrides:
equals in class Object
Parameters:
o - Object to compare to.
Returns:
true iff o is a Graph and o represents the same graph as this object.

hashCode

int hashCode()
Every concrete instantiation of the Graph interface MUST implement the hashCode method, as specified by Object.hashCode(). For graph objects, to ensure consistency with equals(Object), the hash code is defined to be:
 hc=0
 for g in nodes {
   hc=hc+g.hashCode
 }
 for e in edges {
   hc=hc+((e.parent.hashCode)^2)*e.child.hashCode
 }
 return hc
 
where x^2 should be read as "x squared". (Hint: be sure to use integer arithmatic to do the squaring, rather than Math.pow(double, double), which will cast to double.)

This method MUST NOT generate any exceptions.

This method MUST run in O(V+E) time, where V is the number of nodes (vertices) in the graph and E is the number of edges.

Overrides:
hashCode in class Object
Returns:
Hash code for this graph object.

getNodeID

int getNodeID(T node)
              throws GraphStructureException
Return a unique numeric ID code on the range [0,V-1] for the specified node. This function maps every node in the graph to a unique, small, non-negative integer. Such integers can be used, for example, to construct an adjacency matrix representation of the graph.

The returned code MUST be non-negative and MUST be <size() (i.e., the code must be on the range [0,V-1] for a graph with V nodes/vertices). The nodes MAY, however, be ordered in any way, subject to that constraint and the following constraint:

The returned ID code for a node MUST be stable -- calling getNodeID(X), for some node X, MUST return the same ID code, regardless of when it is called, how many times it has been called, whether other nodes have been inserted into the graph in the interim, etc. The code MAY, however, be selected lazily or on node insertion.

If the node is not an element of the graph, this generates a GraphStructureException to indicate the error.

This method MUST run in O(1) time and require at most O(1) space allocation.

Parameters:
node - Graph node for which to generate an ID code
Returns:
Unique integer code for the node
Throws:
GraphStructureException

getNodeByID

T getNodeByID(int nodeID)
              throws GraphStructureException
Return the node corresponding to the specified ID. This operation is the inverse of getNodeID(Object) -- it takes an ID code, and returns the node that corresponds to it. This can be used to retrieve a node, when all you have is a node ID (e.g., for mapping from an adjacency matrix representation of the graph back into an adjacency list).

If the nodeID does not correspond to any node, this generates a GraphStructureException to indicate the error.

This method MUST run in O(1) time and require at most O(1) space allocation.

Parameters:
nodeID - Graph node ID for which to retrieve the node.
Returns:
Node corresponding to the nodeID.
Throws:
GraphStructureException - If nodeID does not exist in the graph.