package fr.orsay.lri.varna.models.treealign; import java.util.*; /** * An object of this class is a rooted tree, where children are ordered. * The tree is iterable, and the default iterator is DFS * (depth-first search), with the fathers given before the children. * * @param <T> The type of values on nodes. * @author Raphael Champeimont */ public class Tree<T> implements Iterable<Tree<T>> { private List<Tree<T>> children; private T value; private Tree<T> tree = this; public T getValue() { return value; } public void setValue(T value) { this.value = value; } /** * Returns the list of children. * The return list has a O(1) access time to any of its elements * (ie. it is like an array and unlike a linked list) */ public List<Tree<T>> getChildren() { return children; } /** * This method replaces the list of children of a tree with the list given * as argument. Be careful, because it means the list will be kept as a * reference (it will not be copied) so if you later modify the list * you passed as an argument here, it will modify the list of children. * Note that the List object you give must have a 0(1) access time to * elements (because someone calling getChildren() can expect that property). * This method may be useful if you have already built a list of children * and you don't want to use this.getChildren.addAll() to avoid a O(n) copy. * In that case you would simply call the constructor that takes no argument * to create an empty tree and then call replaceChildrenListBy(children) * where children is the list of children you have built. * @param children the new list of children */ public void replaceChildrenListBy(List<Tree<T>> children) { this.children = children; } /** * Creates a tree, with the given set of children. * The given set is any collection that implements Iterable<Tree>. * The set is iterated on and its elements are copied (as references). */ public Tree(Iterable<Tree<T>> children) { this(); for (Tree<T> child: children) { this.children.add(child); } } /** * Creates a tree, with an empty list of children. */ public Tree() { children = new ArrayList<Tree<T>>(); } /** * Returns the number of children of the root node. */ public int rootDegree() { return children.size(); } /** * Count the nodes in the tree. * Time: O(n) * @return the number of nodes in the tree */ public int countNodes() { int count = 1; for (Tree<T> child: children) { count += child.countNodes(); } return count; } /** * Compute the tree degree, ie. the max over nodes of the node degree. * Time: O(n) * @return the maximum node degree */ public int computeDegree() { int max = children.size(); for (Tree<T> child: children) { int maxCandidate = child.computeDegree(); if (maxCandidate > max) { max = maxCandidate; } } return max; } /** * Returns a string unique to this node. */ public String toGraphvizNodeId() { return super.toString(); } public Iterator<Tree<T>> iterator() { return (new DFSPrefixIterator()); } /** * An iterator that returns the nodes in prefix (fathers before * children) DFS (go deep first) order. */ public class DFSPrefixIterator implements Iterator<Tree<T>> { private LinkedList<Tree<T>> remainingNodes = new LinkedList<Tree<T>>(); public boolean hasNext() { return !remainingNodes.isEmpty(); } public Tree<T> next() { if (remainingNodes.isEmpty()) { throw (new NoSuchElementException()); } Tree<T> currentNode = remainingNodes.getLast(); remainingNodes.removeLast(); List<Tree<T>> children = currentNode.getChildren(); int n = children.size(); // The children access is in O(1) so this loop is O(n) for (int i=n-1; i>=0; i--) { // We add the children is their reverse order so they // are given in the original order by the iterator remainingNodes.add(children.get(i)); } return currentNode; } public DFSPrefixIterator() { remainingNodes.add(tree); } public void remove() { throw (new UnsupportedOperationException()); } } }