All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uci.ics.jung.graph.DelegateTree Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
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 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();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy