edu.uci.ics.jung.graph.DelegateTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jung-graph-impl Show documentation
Show all versions of jung-graph-impl Show documentation
Graph implementations for the JUNG project
package edu.uci.ics.jung.graph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.common.base.Supplier;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;
/**
* An implementation of Tree
that delegates to
* a specified instance of DirectedGraph
.
* @author Tom Nelson
*
* @param the vertex type
* @param the edge type
*/
@SuppressWarnings("serial")
public class DelegateTree extends GraphDecorator implements Tree
{
/**
* @param the vertex type for the graph Supplier
* @param the edge type for the graph Supplier
* @return a {@code Supplier} that creates an instance of this graph type.
*/
public static final Supplier> getFactory() {
return new Supplier> () {
public Tree get() {
return new DelegateTree(new DirectedSparseMultigraph());
}
};
}
protected V root;
protected Map vertex_depths;
/**
* Creates an instance.
*/
public DelegateTree() {
this(DirectedSparseMultigraph.getFactory());
}
/**
* create an instance with passed values.
* @param graphFactory must create a DirectedGraph to use as a delegate
*/
public DelegateTree(Supplier> graphFactory) {
super(graphFactory.get());
this.vertex_depths = new HashMap();
}
/**
* Creates a new DelegateTree
which delegates to graph
.
* Assumes that graph
is already a tree; if it's not, future behavior
* of this instance is undefined.
* @param graph the graph to which this instance will delegate operations.
*/
public DelegateTree(DirectedGraph graph) {
super(graph);
this.vertex_depths = new HashMap();
}
/**
* Add an edge to the tree, connecting v1, the parent and v2, the child.
* v1 must already exist in the tree, and v2 must not already exist
* the passed edge must be unique in the tree. Passing an edgeType
* other than EdgeType.DIRECTED may cause an illegal argument exception
* in the delegate graph.
*
* @param e a unique edge to add
* @param v1 the parent node
* @param v2 the child node
* @param edgeType should be EdgeType.DIRECTED
* @return true if this call mutates the underlying graph
* @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object, edu.uci.ics.jung.graph.util.EdgeType)
*/
@Override
public boolean addEdge(E e, V v1, V v2, EdgeType edgeType) {
return addChild(e, v1, v2, edgeType);
}
/**
* Add an edge to the tree, connecting v1, the parent and v2, the child.
* v1 must already exist in the tree, and v2 must not already exist
* the passed edge must be unique in the tree.
*
* @param e a unique edge to add
* @param v1 the parent node
* @param v2 the child node
* @return true if this call mutates the underlying graph
* @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object)
*/
@Override
public boolean addEdge(E e, V v1, V v2) {
return addChild(e, v1, v2);
}
/**
* Will set the root of the Tree, only if the Tree is empty and the
* root is currently unset.
*
* @param vertex the tree root to set
* @return true if this call mutates the underlying graph
* @see edu.uci.ics.jung.graph.Graph#addVertex(java.lang.Object)
* @throws UnsupportedOperationException if the root was previously set
*/
@Override
public boolean addVertex(V vertex) {
if(root == null) {
this.root = vertex;
vertex_depths.put(vertex, 0);
return delegate.addVertex(vertex);
} else {
throw new UnsupportedOperationException("Unless you are setting the root, use addChild()");
}
}
/**
* remove the passed node, and all nodes that are descendants of the
* passed node.
* @param vertex the vertex to remove
* @return true
iff the tree was modified
* @see edu.uci.ics.jung.graph.Graph#removeVertex(java.lang.Object)
*/
@Override
public boolean removeVertex(V vertex) {
if (!delegate.containsVertex(vertex))
return false;
for(V v : getChildren(vertex)) {
removeVertex(v);
vertex_depths.remove(v);
}
// recalculate height
vertex_depths.remove(vertex);
return delegate.removeVertex(vertex);
}
/**
* add the passed child node as a child of parent.
* parent must exist in the tree, and child must not already exist.
*
* @param edge the unique edge to connect the parent and child nodes
* @param parent the existing parent to attach the child to
* @param child the new child to add to the tree as a child of parent
* @param edgeType must be EdgeType.DIRECTED or the underlying graph may throw an exception
* @return whether this call mutates the underlying graph
*/
public boolean addChild(E edge, V parent, V child, EdgeType edgeType) {
Collection vertices = delegate.getVertices();
if(vertices.contains(parent) == false) {
throw new IllegalArgumentException("Tree must already contain parent "+parent);
}
if(vertices.contains(child)) {
throw new IllegalArgumentException("Tree must not already contain child "+child);
}
vertex_depths.put(child, vertex_depths.get(parent) + 1);
return delegate.addEdge(edge, parent, child, edgeType);
}
/**
* add the passed child node as a child of parent.
* parent must exist in the tree, and child must not already exist
* @param edge the unique edge to connect the parent and child nodes
* @param parent the existing parent to attach the child to
* @param child the new child to add to the tree as a child of parent
* @return whether this call mutates the underlying graph
*/
public boolean addChild(E edge, V parent, V child) {
Collection vertices = delegate.getVertices();
if(vertices.contains(parent) == false) {
throw new IllegalArgumentException("Tree must already contain parent "+parent);
}
if(vertices.contains(child)) {
throw new IllegalArgumentException("Tree must not already contain child "+child);
}
vertex_depths.put(child, vertex_depths.get(parent) + 1);
return delegate.addEdge(edge, parent, child);
}
/**
* get the number of children of the passed parent node
*/
public int getChildCount(V parent) {
if (!delegate.containsVertex(parent))
return 0;
return getChildren(parent).size();
}
/**
* get the immediate children nodes of the passed parent
*/
public Collection getChildren(V parent) {
if (!delegate.containsVertex(parent))
return null;
return delegate.getSuccessors(parent);
}
/**
* get the single parent node of the passed child
*/
public V getParent(V child) {
if (!delegate.containsVertex(child))
return null;
Collection predecessors = delegate.getPredecessors(child);
if(predecessors.size() == 0) {
return null;
}
return predecessors.iterator().next();
}
/**
* Returns an ordered list of the nodes beginning at the root
* and ending at {@code vertex}, including all intermediate
* nodes.
* @param vertex the last node in the path from the root
* @return an ordered list of the nodes from root to child
*/
public List getPath(V vertex) {
if (!delegate.containsVertex(vertex))
return null;
List vertex_to_root = new ArrayList();
vertex_to_root.add(vertex);
V parent = getParent(vertex);
while(parent != null) {
vertex_to_root.add(parent);
parent = getParent(parent);
}
// reverse list so that it goes from root to child
List root_to_vertex = new ArrayList(vertex_to_root.size());
for (int i = vertex_to_root.size() - 1; i >= 0; i--)
root_to_vertex.add(vertex_to_root.get(i));
return root_to_vertex;
}
/**
* getter for the root of the tree
* @return the root
*/
public V getRoot() {
return root;
}
/**
* sets the root to the passed value, only if the root is
* previously unset
* @param root the initial tree root
*/
public void setRoot(V root) {
addVertex(root);
}
/**
* removes a node from the tree, causing all descendants of
* the removed node also to be removed
* @param orphan the node to remove
* @return whether this call mutates the underlying graph
*/
public boolean removeChild(V orphan) {
return removeVertex(orphan);
}
/**
* computes and returns the depth of the tree from the
* root to the passed vertex
*
* @param v the node who's depth is computed
* @return the depth to the passed node.
*/
public int getDepth(V v) {
return this.vertex_depths.get(v);
}
/**
* Computes and returns the height of the tree.
*
* @return the height
*/
public int getHeight() {
int height = 0;
for(V v : getVertices()) {
height = Math.max(height, getDepth(v));
}
return height;
}
/**
* @param v the vertex to test
* @return true
if v
is neither
* a leaf nor the root of this tree
*/
public boolean isInternal(V v) {
if (!delegate.containsVertex(v))
return false;
return isLeaf(v) == false && isRoot(v) == false;
}
/**
* @param v the vertex to test
* @return true
if {@code v} has no children
*/
public boolean isLeaf(V v) {
if (!delegate.containsVertex(v))
return false;
return getChildren(v).size() == 0;
}
/**
* @param v the vertex to test
* @return true
if {@code v} has no parent
*/
public boolean isRoot(V v) {
if (!delegate.containsVertex(v))
return false;
return getParent(v) == null;
}
@Override
public int getIncidentCount(E edge)
{
if (!delegate.containsEdge(edge))
return 0;
// all edges in a tree connect exactly 2 vertices
return 2;
}
@SuppressWarnings("unchecked")
@Override
public boolean addEdge(E edge, Collection extends V> vertices) {
Pair pair = null;
if(vertices instanceof Pair) {
pair = (Pair)vertices;
} else {
pair = new Pair(vertices);
}
return addEdge(edge, pair.getFirst(), pair.getSecond());
}
@Override
public String toString() {
return "Tree of "+delegate.toString();
}
public Collection> getTrees() {
return Collections.>singleton(this);
}
public Collection getChildEdges(V vertex) {
return getOutEdges(vertex);
}
public E getParentEdge(V vertex) {
return getInEdges(vertex).iterator().next();
}
}