org.openforis.commons.collection.Tree Maven / Gradle / Ivy
package org.openforis.commons.collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Stack;
/**
*
* @author S. Ricci
*
* @param
*/
public class Tree {
private Node root;
private Map> itemToNode;
public enum TraversalType {
BFS, DFS
}
public Tree() {
this(null);
}
public Tree(T rootItem) {
this.itemToNode = new HashMap>();
this.root = createNode(rootItem);
itemToNode.put(rootItem, this.root);
}
public Node getRoot() {
return root;
}
public Node findNodeByItem(T item) {
return itemToNode.get(item);
}
public void reparent(Node node, Node newParent) {
node.parent.removeChild(node);
newParent.addChild(node);
}
public List getItems() {
final List result = new ArrayList();
traverse(new NodeVisitor() {
@Override
public void visit(Node node) {
T item = node.item;
if ( item != null ) {
result.add(item);
}
}
}, TraversalType.BFS);
return result;
}
public void traverse(NodeVisitor visitor) {
traverse(visitor, TraversalType.DFS);
}
public void traverse(NodeVisitor visitor, TraversalType traversalType) {
switch (traversalType) {
case BFS:
bfsTraverse(visitor);
break;
default:
dfsTraverse(visitor);
break;
}
}
protected void dfsTraverse(NodeVisitor visitor) {
Stack> stack = new Stack>();
stack.push(root);
while ( ! stack.isEmpty() ) {
Node node = stack.pop();
visitor.visit(node);
stack.addAll(node.children);
}
}
protected void bfsTraverse(NodeVisitor visitor) {
Queue> queue = new LinkedList>();
queue.add(this.root);
while ( ! queue.isEmpty() ) {
Node node = queue.poll();
visitor.visit(node);
queue.addAll(node.getChildren());
}
}
public Node createNode(T item) {
return new Node(this, item);
}
public static interface NodeVisitor {
void visit(Node node);
}
public static class Node {
private Tree tree;
private Node parent;
private T item;
private List> children;
private Node(Tree tree) {
this.tree = tree;
this.children = new ArrayList>();
}
private Node(Tree tree, T item) {
this(tree);
this.item = item;
}
public void addChild(Node node) {
children.add(node);
node.parent = this;
tree.itemToNode.put(node.item, node);
}
public void removeChild(Node node) {
children.remove(node);
node.parent = null;
tree.itemToNode.remove(node.item);
}
public List> getChildren() {
return CollectionUtils.unmodifiableList(children);
}
public int getDepth() {
Node currentParent = parent;
int result = 0;
while ( currentParent != null ) {
result ++;
currentParent = currentParent.parent;
}
return result;
}
public boolean isDetached() {
return parent == null;
}
}
}