Commit 1ecf2087 authored by Paul Fiterau Brostean's avatar Paul Fiterau Brostean
Browse files

added generictree from tomte

parent 5e693c02
package generictree;
import generictree.GenericTreeIteratorDepthFirstPreOrder;
import generictree.GenericTreeNode;
import java.util.*;
import java.lang.Iterable;
public class GenericTree<T> implements Iterable<GenericTreeNode<T>> {
private GenericTreeNode<T> root;
//private Iterator<GenericTreeNode<T>> iterator;
private GenericTreeIterator<GenericTreeNode<T>> iterator;
public GenericTree() {
super();
}
public GenericTree<T> getShallowCopy() {
GenericTree<T> shallowCopy= new GenericTree<T>();
shallowCopy.setRoot(this.getRoot());
return shallowCopy;
}
public GenericTreeNode<T> getRoot() {
return this.root;
}
public void setRoot(GenericTreeNode<T> root) {
this.root = root;
this.iterator=new GenericTreeIteratorDepthFirstPreOrder<T>(root);
}
public boolean isEmpty() {
return (root == null);
}
// add iterator to GenericTree
public void setIterator( GenericTreeIterator<GenericTreeNode<T>> iteratorIn ) {
this.iterator=iteratorIn;
}
public GenericTreeIterator<GenericTreeNode<T>> iterator() {
return this.iterator.newInstance();
}
public String toStringNew() {
/*
GenericTreeIteratorDepthFirstPreOrder<String> it = new GenericTreeIteratorDepthFirstPreOrder<String>(root);
int i = 0;
while (it.hasNext( )) {
Object o = it.next( );
System.out.println("Element " + i++ + " = " + o);
}
*/
ArrayList<String> str= new ArrayList<String>();
//int i = 0;
for(GenericTreeNode<T> node : this) {
str.add(node.toString());
}
return str.toString();
/*
str="";
for(GenericTreeNode<T> node : this) {
str= str + node.toString();
}
return str;
*/
}
public int getNumberOfNodes() {
int numberOfNodes = 0;
if(root != null) {
numberOfNodes = auxiliaryGetNumberOfNodes(root) + 1; //1 for the root!
}
return numberOfNodes;
}
private int auxiliaryGetNumberOfNodes(GenericTreeNode<T> node) {
int numberOfNodes = node.getNumberOfChildren();
for(GenericTreeNode<T> child : node.getChildren()) {
numberOfNodes += auxiliaryGetNumberOfNodes(child);
}
return numberOfNodes;
}
public int getNumberOfEndNodes() {
int numberOfEndNodes = 0;
if(root != null) {
numberOfEndNodes = auxiliaryGetNumberOfEndNodes(root);
}
return numberOfEndNodes;
}
private int auxiliaryGetNumberOfEndNodes(GenericTreeNode<T> node) {
int numberOfEndNodes = 0;
if (node.getNumberOfChildren() == 0 ) return 1;
for(GenericTreeNode<T> child : node.getChildren()) {
numberOfEndNodes += auxiliaryGetNumberOfEndNodes(child);
}
return numberOfEndNodes;
}
public Map <Integer,Integer> depthIndex() {
int depth=0;
Map <Integer,Integer> depth2numNodes= new HashMap <Integer,Integer> ();
if(root != null) {
depth2numNodes.put(depth, 1);
depth2numNodes=auxiliaryDepthIndex(root,depth2numNodes,depth);
}
return depth2numNodes;
}
private Map <Integer,Integer> auxiliaryDepthIndex(GenericTreeNode<T> node,Map <Integer,Integer> depth2numNodes,int depth) {
// fetch number of children; if that is 0, then nothing to do and return
int numChildren=node.getNumberOfChildren();
if ( numChildren == 0 ) return depth2numNodes;
// Let's add the number of nodes which are child of current node to the depth2numNodes map.
// So we have to increase depth with 1 to get the depth of the child nodes
depth++;
// Fetch the number of nodes already found at this depth
int numNodes;
if ( depth2numNodes.containsKey(depth) ) {
numNodes=depth2numNodes.get(depth);
} else {
numNodes=0;
}
// Set numNodes in array with value : already found nodes + num of children of current node
depth2numNodes.put(depth,numNodes+numChildren);
// repeat this procedure for the each of the child nodes
for(GenericTreeNode<T> child : node.getChildren()) {
depth2numNodes = auxiliaryDepthIndex(child,depth2numNodes,depth);
}
return depth2numNodes;
}
public List<GenericTreeNode<T>> getNodeTrace(GenericTreeNode<T> currentNode) {
ArrayList<GenericTreeNode<T>> returnList = null;
if(root != null) {
returnList=new ArrayList<GenericTreeNode<T>> ();
this.setIterator(new GenericTreeIteratorUpwards<T>(currentNode));
for(GenericTreeNode<T> node : this) {
returnList.add(node);
}
Collections.reverse(returnList);
}
return returnList;
}
//-------------------------------------------------------------------------------------------------
/// think below is obsolete -> use iterator loop instead!
//-------------------------------------------------------------------------------------------------
//TODO: find should use set traversal method!
public boolean exists(T dataToFind) {
return (find(dataToFind) != null);
}
public GenericTreeNode<T> find(T dataToFind) {
GenericTreeNode<T> returnNode = null;
if(root != null) {
returnNode = auxiliaryFind(root, dataToFind);
}
return returnNode;
}
private GenericTreeNode<T> auxiliaryFind(GenericTreeNode<T> currentNode, T dataToFind) {
GenericTreeNode<T> returnNode = null;
int i = 0;
if (currentNode.getData().equals(dataToFind)) {
returnNode = currentNode;
}
else if(currentNode.hasChildren()) {
i = 0;
while(returnNode == null && i < currentNode.getNumberOfChildren()) {
returnNode = auxiliaryFind(currentNode.getChildAt(i), dataToFind);
i++;
}
}
return returnNode;
}
// map tree to a flat ArrayList (fixed order of insertion) or a LinkedHashMap (preserves iteration order : This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).!)
public List<GenericTreeNode<T>> build(GenericTreeTraversalOrderEnum traversalOrder) {
List<GenericTreeNode<T>> returnList = null;
if(root != null) {
returnList = build(root, traversalOrder);
}
return returnList;
}
public List<GenericTreeNode<T>> build(GenericTreeNode<T> node, GenericTreeTraversalOrderEnum traversalOrder) {
List<GenericTreeNode<T>> traversalResult = new ArrayList<GenericTreeNode<T>>();
if(traversalOrder == GenericTreeTraversalOrderEnum.PRE_ORDER) {
buildPreOrder(node, traversalResult);
}
else if(traversalOrder == GenericTreeTraversalOrderEnum.POST_ORDER) {
buildPostOrder(node, traversalResult);
}
return traversalResult;
}
private void buildPreOrder(GenericTreeNode<T> node, List<GenericTreeNode<T>> traversalResult) {
traversalResult.add(node);
for(GenericTreeNode<T> child : node.getChildren()) {
buildPreOrder(child, traversalResult);
}
}
private void buildPostOrder(GenericTreeNode<T> node, List<GenericTreeNode<T>> traversalResult) {
for(GenericTreeNode<T> child : node.getChildren()) {
buildPostOrder(child, traversalResult);
}
traversalResult.add(node);
}
public Map<GenericTreeNode<T>, Integer> buildWithDepth(GenericTreeTraversalOrderEnum traversalOrder) {
Map<GenericTreeNode<T>, Integer> returnMap = null;
if(root != null) {
returnMap = buildWithDepth(root, traversalOrder);
}
return returnMap;
}
public Map<GenericTreeNode<T>, Integer> buildWithDepth(GenericTreeNode<T> node, GenericTreeTraversalOrderEnum traversalOrder) {
Map<GenericTreeNode<T>, Integer> traversalResult = new LinkedHashMap<GenericTreeNode<T>, Integer>();
if(traversalOrder == GenericTreeTraversalOrderEnum.PRE_ORDER) {
buildPreOrderWithDepth(node, traversalResult, 0);
}
else if(traversalOrder == GenericTreeTraversalOrderEnum.POST_ORDER) {
buildPostOrderWithDepth(node, traversalResult, 0);
}
return traversalResult;
}
private void buildPreOrderWithDepth(GenericTreeNode<T> node, Map<GenericTreeNode<T>, Integer> traversalResult, int depth) {
traversalResult.put(node, depth);
for(GenericTreeNode<T> child : node.getChildren()) {
buildPreOrderWithDepth(child, traversalResult, depth + 1);
}
}
private void buildPostOrderWithDepth(GenericTreeNode<T> node, Map<GenericTreeNode<T>, Integer> traversalResult, int depth) {
for(GenericTreeNode<T> child : node.getChildren()) {
buildPostOrderWithDepth(child, traversalResult, depth + 1);
}
traversalResult.put(node, depth);
}
public String toString() {
/*
We're going to assume a pre-order traversal by default
*/
String stringRepresentation = "";
if(root != null) {
stringRepresentation = build(GenericTreeTraversalOrderEnum.PRE_ORDER).toString();
}
return stringRepresentation;
}
public String toStringWithDepth() {
/*
We're going to assume a pre-order traversal by default
*/
String stringRepresentation = "";
if(root != null) {
stringRepresentation = buildWithDepth(GenericTreeTraversalOrderEnum.PRE_ORDER).toString();
}
return stringRepresentation;
}
}
package generictree;
import java.util.Iterator;
public interface GenericTreeIterator<E> extends Iterator<E> {
public E getStartNode();
public void setStartNode(E startNode);
//public void reset();
public GenericTreeIterator<E> newInstance();
}
package generictree;
public abstract class GenericTreeIteratorAbstract<T> {
/** The data to be iterated over. */
protected GenericTreeNode<T> startNode;
protected GenericTreeNode<T> nextNode;
/** Construct an GenericTreeIterator object.
* @param startNode The root Node of the tree to be iterated over.
*/
public GenericTreeIteratorAbstract(GenericTreeNode<T> startNode) {}
/** Reset the iterator.
*/
public void reset(){};
/** Set the root Node to the given startNode, and reset the iterator.
* @param startNode The root Node of the tree to be iterated over.
* Note: by creating a GenericTreeIterator with a root node set
* to some node in a bigger tree, we effectively have the
* iterator only iterating through the subtree of the bigger
* tree starting at the startNode!
*/
public void setStartNode(GenericTreeNode<T> startNode) {
this.startNode = startNode;
this.reset();
}
public GenericTreeNode<T> getStartNode() {
return this.startNode;
}
/** Fetches the next node from the tree,
* Note: this function is only called when next node exists!
* That is : fetchNext() is only called when hasNext() returns true!
*/
abstract public GenericTreeNode<T> fetchNext() ;
/**
* Tell if there are any more nodes in tree to traversal.
* @return true if not at the end, i.e., if next( ) will succeed.
* @return false if next( ) will throw an exception.
*/
public boolean hasNext() {
return ( this.nextNode != null ) ;
}
/** Returns the next node from the tree */
public GenericTreeNode<T> next() {
if (hasNext()) {
return fetchNext();
}
throw new IndexOutOfBoundsException("no nodes in tree to traversal anymore");
}
/** Remove the object that next( ) just returned.
* An Iterator is not required to support this interface,
* and we certainly don't!
*/
public void remove() {
throw new UnsupportedOperationException(
"This demo does not implement the remove method");
}
}
\ No newline at end of file
package generictree;
import java.util.LinkedList;
public class GenericTreeIteratorBreadthFirst<T> extends GenericTreeIteratorAbstract<T> implements GenericTreeIterator<GenericTreeNode<T>> {
protected LinkedList<GenericTreeNode<T>> currentLevelNodeCache = new LinkedList<GenericTreeNode<T>>();
protected LinkedList<GenericTreeNode<T>> nextLevelNodeCache = new LinkedList<GenericTreeNode<T>>();
// nodeCache uses queue (LIFO) interface of linked list, choosen for fast add(at end) and remove(at begin) LIFO style )
/** Construct an GenericTreeIteratorBreadthFirst object.
* @param startNode The node of the tree where to start the iteration.
*/
public GenericTreeIteratorBreadthFirst(GenericTreeNode<T> startNode) {
super(startNode);
setStartNode(startNode);
}
public GenericTreeIteratorBreadthFirst<T> newInstance() {
return new GenericTreeIteratorBreadthFirst<T>(this.startNode);
}
/** Reset the iterator.
*/
public void reset() {
this.nextNode=this.startNode;
}
/* gets new value for this.nextNode
* Note: if no next node node is found it return null
*/
GenericTreeNode<T> getNextNode() {
this.nextLevelNodeCache.addAll(this.nextNode.getChildren());
// find new this.nextNode node
if ( this.currentLevelNodeCache.isEmpty() ) {
if ( this.nextLevelNodeCache.isEmpty() ) {
// no more nodes left in tree
return null;
}
this.currentLevelNodeCache=this.nextLevelNodeCache;
this.nextLevelNodeCache= new LinkedList<GenericTreeNode<T>>();
}
return this.currentLevelNodeCache.remove(); // remove from begin queue and return node
}
/** Fetches the next node from the tree,
* Note: this function is only called when next node exists!
*/
public GenericTreeNode<T> fetchNext() {
// this.nextNode becomes node to return
GenericTreeNode<T> node=this.nextNode;
// prefetch next node for next call to this method
// getNextNode() will return null if whole tree is reached
// note: if this.nextNode is set to null then hasNext() will on next call return false on iteration will stop!
this.nextNode=getNextNode();
return node;
}
}
package generictree;
import java.util.Stack;
import java.util.LinkedList;
public class GenericTreeIteratorDepthFirstPostOrder<T> extends GenericTreeIteratorAbstract<T> implements GenericTreeIterator<GenericTreeNode<T>> {
protected Stack<Integer> childIndexes = new Stack<Integer>();
// childIndexes use stack interface (FIFO), choosen for fast push(end) and pop(end) FIFO style
protected int currentNodeIndex;
protected LinkedList<GenericTreeNode<T>> nodeCache = new LinkedList<GenericTreeNode<T>>();
// nodeCache uses queue (LIFO) interface of linked list, choosen for fast add(end) and remove(begin) LIFO style )
protected GenericTreeNode<T> currentNode; // position where you are in tree walk
//protected int currentDepth;
/** Construct an GenericTreeIteratorDepthFirstPostOrder object.
* @param startNode The node of the tree where to start the iteration.
*/
public GenericTreeIteratorDepthFirstPostOrder(GenericTreeNode<T> startNode) {
super(startNode);
setStartNode(startNode);
}
public GenericTreeIteratorDepthFirstPostOrder<T> newInstance() {
return new GenericTreeIteratorDepthFirstPostOrder<T>(this.startNode);
}
/** Reset the iterator.
*/
public void reset() {
this.nextNode=this.startNode;
this.currentNode=this.startNode;
}
private void walkMostLeftDownwards( ) {
if ( this.currentNode.hasChildren() ) {
//System.out.println("store index of node: " + this.currentNode.toString()); //debug
this.childIndexes.push(this.currentNodeIndex);
this.currentNode=this.currentNode.getChildAt(0);
this.currentNodeIndex=0;
walkMostLeftDownwards();
} else {
//System.out.println("down : add current node to cache: " + this.currentNode.toString()); //debug
this.nodeCache.add(this.currentNode); // add at end queue
}
}
private void walkToNextSibling() {
if ( this.currentNode == this.startNode ) {
// we are back at root, so we are finished walking
this.currentNode=null;
return;
}
if ( this.currentNodeIndex + 1 < this.currentNode.getParent().getNumberOfChildren() ) {
//System.out.println("parent: " + this.currentNode.getParent().toString()); //debug
//System.out.println("parent: " + this.currentNode.getParent().getNumberOfChildren()); //debug
//System.out.println("child index: " + this.currentNodeIndex); //debug
// get right sibling
this.currentNodeIndex++;
this.currentNode=this.currentNode.getParent().getChildAt(this.currentNodeIndex);
//System.out.println("sibbling: " + this.currentNode.toString()); //debug
//System.out.println("sibbling index: " + this.currentNodeIndex); //debug
} else {
// go one node upwards and try walkToNextSibling again
this.currentNode=this.currentNode.getParent();
this.currentNodeIndex=this.childIndexes.pop();
//System.out.println("upwards : add current node to cache: " + this.currentNode.toString()); //debug
this.nodeCache.add(this.currentNode); // add at end queue
walkToNextSibling();
}
}
private void walkToNextRightDownwardsSibling() {
// walk from parent downwards to first child repeatedly
walkMostLeftDownwards();
// try to find sibbling or else parents sibling or parent-parents sibling etc..
walkToNextSibling();
}
/* gets new value for this.nextNode
* Note: if no next node node is found it return null
*/
GenericTreeNode<T> getNextNode() {
// find new this.nextNode node
if ( this.nodeCache.isEmpty() && this.currentNode != null ) {
// nodeCache is empty so we must walk through to collect nodes in cache
// note: this.currentNode == null means we are finished walking
walkToNextRightDownwardsSibling(); // puts passing nodes at end of cache queue
}
if ( this.nodeCache.isEmpty() ) { // if true: this.currentNode should be null
// no new nodes found by walking -> at end of walk through tree
return null;
} else {
return this.nodeCache.remove(); // remove from begin queue and return node
}
}