This project is available on github. Please download from there to make sure you have the latest version.
Last week I was solving a problem at work that required the use of a Generic (n-ary) Tree. An n-ary tree is a tree where node can have between 0 and n children. There is a special case of n-ary trees where each node can have at most n nodes (k-ary tree). This implementation focuses on the most general case, where any node can have between 0 and n children. Java doesn’t have a Tree or Tree Node data structure. I couldn’t find any third-party implementations either (like in commons-lang). So I decided to write my own.
First, we need to define the node of our tree. Our node has two attributes. One is the data, and another is a List which can contain references to the children of that node:
The code for a Generic Tree Node looks like this:
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GenericTreeNode<T> {
public T data;
public List<GenericTreeNode<T>> children;
public GenericTreeNode() {
super();
children = new ArrayList<GenericTreeNode<T>>();
}
public GenericTreeNode(T data) {
this();
setData(data);
}
public List<GenericTreeNode<T>> getChildren() {
return this.children;
}
public int getNumberOfChildren() {
return getChildren().size();
}
public boolean hasChildren() {
return (getNumberOfChildren() > 0);
}
public void setChildren(List<GenericTreeNode<T>> children) {
this.children = children;
}
public void addChild(GenericTreeNode<T> child) {
children.add(child);
}
public void addChildAt(int index, GenericTreeNode<T> child) throws IndexOutOfBoundsException {
children.add(index, child);
}
public void removeChildren() {
this.children = new ArrayList<GenericTreeNode<T>>();
}
public void removeChildAt(int index) throws IndexOutOfBoundsException {
children.remove(index);
}
public GenericTreeNode<T> getChildAt(int index) throws IndexOutOfBoundsException {
return children.get(index);
}
public T getData() {
return this.data;
}
public void setData(T data) {
this.data = data;
}
public String toString() {
return getData().toString();
}
public boolean equals(GenericTreeNode<T> node) {
return node.getData().equals(getData());
}
public int hashCode() {
return getData().hashCode();
}
public String toStringVerbose() {
String stringRepresentation = getData().toString() + ":[";
for (GenericTreeNode<T> node : getChildren()) {
stringRepresentation += node.getData().toString() + ", ";
}
//Pattern.DOTALL causes ^ and $ to match. Otherwise it won't. It's retarded.
Pattern pattern = Pattern.compile(", $", Pattern.DOTALL);
Matcher matcher = pattern.matcher(stringRepresentation);
stringRepresentation = matcher.replaceFirst("");
stringRepresentation += "]";
return stringRepresentation;
}
}
After writing a class for a Generic Tree Node, we need to write a Generic Tree class, which will use Generic Tree Nodes to build a Generic Tree:
public enum GenericTreeTraversalOrderEnum {
PRE_ORDER,
POST_ORDER
}
import java.util.*;
public class GenericTree<T> {
private GenericTreeNode<T> root;
public GenericTree() {
super();
}
public GenericTreeNode<T> getRoot() {
return this.root;
}
public void setRoot(GenericTreeNode<T> root) {
this.root = root;
}
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 boolean exists(GenericTreeNode<T> nodeToFind) {
return (find(nodeToFind) != null);
}
public GenericTreeNode<T> find(GenericTreeNode<T> nodeToFind) {
GenericTreeNode<T> returnNode = null;
if(root != null) {
returnNode = auxiliaryFind(root, nodeToFind);
}
return returnNode;
}
private GenericTreeNode<T> auxiliaryFind(GenericTreeNode<T> currentNode, GenericTreeNode<T> nodeToFind) {
GenericTreeNode<T> returnNode = null;
int i = 0;
if (currentNode.equals(nodeToFind)) {
returnNode = currentNode;
}
else if(currentNode.hasChildren()) {
i = 0;
while(returnNode == null && i < currentNode.getNumberOfChildren()) {
returnNode = auxiliaryFind(currentNode.getChildAt(i), nodeToFind);
i++;
}
}
return returnNode;
}
public boolean isEmpty() {
return (root == null);
}
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;
}
}
Creating the tree is pretty simple. Here is a snippet:
/*
We're building a tree that looks like this:
I am root!
/\
A B
/\
C D
\
E
*/
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>("I am root!");
GenericTreeNode<String> childA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
GenericTreeNode<String> childE = new GenericTreeNode<String>("E");
childD.addChild(childE);
childB.addChild(childC);
childB.addChild(childD);
root.addChild(childA);
root.addChild(childB);
tree.setRoot(root);
Of course, simply writing a data structure is not enough. We need tests!
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import static org.testng.Assert.*;
public class TestGenericTreeNode {
@Test
public void TestNodeDataIsNullOnNewNodeCreation() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
assertNull(node.getData());
}
@Test
public void TestNodeHasNonNullChildrenListOnNewNodeCreation() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
assertNotNull(node.getChildren());
}
@Test
public void TestNodeHasZeroChildrenOnNewNodeCreation() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
assertEquals(node.getNumberOfChildren(), 0);
}
@Test
public void TestNodeHasChildrenReturnsFalseOnNewNodeCreation() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
assertFalse(node.hasChildren());
}
@Test
public void TestNodeDataIsNonNullWithParameterizedConstructor() {
GenericTreeNode<String> node = new GenericTreeNode<String>("I haz data");
assertNotNull(node.getData());
}
@Test
public void TestNodeSetAndGetData() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
String data = "data";
node.setData(data);
assertEquals(node.getData(), data);
}
@Test
public void TestNodeSetAndGetChildren() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
GenericTreeNode<String> child = new GenericTreeNode<String>();
List<GenericTreeNode<String>> children = new ArrayList<GenericTreeNode<String>>();
children.add(child);
node.setChildren(children);
assertEquals(node.getChildren(), children);
}
@Test
public void TestNodeRemoveChildren() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
GenericTreeNode<String> child = new GenericTreeNode<String>();
List<GenericTreeNode<String>> children = new ArrayList<GenericTreeNode<String>>();
children.add(child);
node.setChildren(children);
node.removeChildren();
assertEquals(node.getChildren().size(), 0);
}
@Test
public void TestNodeAddChildHasOneChild() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
GenericTreeNode<String> child = new GenericTreeNode<String>();
node.addChild(child);
assertEquals(node.getNumberOfChildren(), 1);
}
@Test
public void TestNodeAddChildHasChildrenIsTrue() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
GenericTreeNode<String> child = new GenericTreeNode<String>();
node.addChild(child);
assertTrue(node.hasChildren());
}
@Test
public void TestNodeAddAndGetChildAt() {
GenericTreeNode<String> node = new GenericTreeNode<String>("root");
GenericTreeNode<String> child1 = new GenericTreeNode<String>("child1");
GenericTreeNode<String> child2 = new GenericTreeNode<String>("child2");
node.addChild(child1);
node.addChildAt(1, child2);
assertEquals(node.getChildAt(1).getData(), child2.getData());
}
@Test
public void TestNodeAddAndRemoveChildAt() {
GenericTreeNode<String> node = new GenericTreeNode<String>("root");
GenericTreeNode<String> child1 = new GenericTreeNode<String>("child1");
GenericTreeNode<String> child2 = new GenericTreeNode<String>("child2");
node.addChild(child1);
node.addChildAt(1, child2);
node.removeChildAt(0);
assertEquals(node.getNumberOfChildren(), 1);
}
@Test(expectedExceptions = java.lang.IndexOutOfBoundsException.class)
public void TestNodeAddChildAtThrowsException() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
GenericTreeNode<String> child = new GenericTreeNode<String>();
node.addChildAt(5, child);
}
@Test(expectedExceptions = java.lang.IndexOutOfBoundsException.class)
public void TestNodeRemoveChildAtThrowsException() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
node.removeChildAt(1);
}
@Test
public void TestNodeToString() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
node.setData("data");
assertEquals(node.toString(), "data");
}
@Test
public void TestNodeToStringVerboseNoChildren() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
node.setData("data");
assertEquals(node.toStringVerbose(), "data:[]");
}
@Test
public void TestNodeToStringVerboseOneChild() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
node.setData("data");
GenericTreeNode<String> child = new GenericTreeNode<String>();
child.setData("child");
node.addChild(child);
assertEquals(node.toStringVerbose(), "data:[child]");
}
@Test
public void TestNodeToStringVerboseMoreThanOneChild() {
GenericTreeNode<String> node = new GenericTreeNode<String>();
node.setData("data");
GenericTreeNode<String> child1 = new GenericTreeNode<String>();
child1.setData("child1");
GenericTreeNode<String> child2 = new GenericTreeNode<String>();
child2.setData("child2");
node.addChild(child1);
node.addChild(child2);
assertEquals(node.toStringVerbose(), "data:[child1, child2]");
}
}
import org.testng.annotations.Test;
import java.util.*;
import static org.testng.Assert.*;
public class TestGenericTree {
@Test
public void TestRootIsNullOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertNull(tree.getRoot());
}
@Test
public void TestNumberOfNodesIsZeroOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertEquals(tree.getNumberOfNodes(), 0);
}
@Test
public void TestIsEmptyIsTrueOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertTrue(tree.isEmpty());
}
@Test
void TestExistsIsFalseOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> nodeToFind = new GenericTreeNode<String>();
assertFalse(tree.exists(nodeToFind));
}
@Test
void TestFindReturnsNullOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> nodeToFind = new GenericTreeNode<String>();
assertNull(tree.find(nodeToFind));
}
@Test
void TestPreOrderBuildReturnsNullListOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertNull(tree.build(GenericTreeTraversalOrderEnum.PRE_ORDER));
}
@Test
void TestPostOrderBuildReturnsNullListOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertNull(tree.build(GenericTreeTraversalOrderEnum.POST_ORDER));
}
@Test
void TestPreOrderBuildWithDepthReturnsNullMapOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertNull(tree.buildWithDepth(GenericTreeTraversalOrderEnum.PRE_ORDER));
}
@Test
void TestPostOrderBuildWithDepthReturnsNullMapOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertNull(tree.buildWithDepth(GenericTreeTraversalOrderEnum.POST_ORDER));
}
@Test
void TestToStringReturnsEmptyStringOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertEquals(tree.toString(), "");
}
@Test
void TestToStringWithDepthReturnsEmptyStringOnNewTreeCreation() {
GenericTree<String> tree = new GenericTree<String>();
assertEquals(tree.toStringWithDepth(), "");
}
@Test
void TestSetRootGetRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>();
tree.setRoot(root);
assertNotNull(tree.getRoot());
}
@Test
void TestNumberOfNodesIsOneWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>();
tree.setRoot(root);
assertEquals(tree.getNumberOfNodes(), 1);
}
@Test
void TestEmptyIsFalseWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>();
tree.setRoot(root);
assertFalse(tree.isEmpty());
}
@Test
void TestPreOrderBuildListSizeIsOneWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>("root");
tree.setRoot(root);
assertEquals(tree.build(GenericTreeTraversalOrderEnum.PRE_ORDER).size(), 1);
}
@Test
void TestPostOrderBuildListSizeIsOneWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>("root");
tree.setRoot(root);
assertEquals(tree.build(GenericTreeTraversalOrderEnum.POST_ORDER).size(), 1);
}
@Test
void TestPreOrderBuildWithDepthSizeIsOneWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>("root");
tree.setRoot(root);
assertEquals(tree.buildWithDepth(GenericTreeTraversalOrderEnum.PRE_ORDER).size(), 1);
}
@Test
void TestPostOrderBuildWithDepthSizeIsOneWithNonNullRoot() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> root = new GenericTreeNode<String>("root");
tree.setRoot(root);
assertEquals(tree.buildWithDepth(GenericTreeTraversalOrderEnum.POST_ORDER).size(), 1);
}
/*
Tree looks like:
A
/ \
B C
\
D
For the following tests
*/
@Test
void TestNumberOfNodes() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
assertEquals(tree.getNumberOfNodes(), 4);
}
@Test
void TestExistsReturnsTrue() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
GenericTreeNode<String> nodeToFindD = new GenericTreeNode<String>("D");
assertTrue(tree.exists(nodeToFindD));
}
@Test
void TestFindReturnsNonNull() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
GenericTreeNode<String> nodeToFindD = new GenericTreeNode<String>("D");
assertNotNull(tree.find(nodeToFindD));
}
@Test
void TestExistsReturnsFalse() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
GenericTreeNode<String> nodeToFindE = new GenericTreeNode<String>("E");
assertFalse(tree.exists(nodeToFindE));
}
@Test
void TestFindReturnsNull() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
GenericTreeNode<String> nodeToFindE = new GenericTreeNode<String>("E");
assertNull(tree.find(nodeToFindE));
}
// Pre-order traversal will give us A B C D
@Test
void TestPreOrderBuild() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
List<GenericTreeNode<String>> preOrderList = new ArrayList<GenericTreeNode<String>>();
preOrderList.add(new GenericTreeNode<String>("A"));
preOrderList.add(new GenericTreeNode<String>("B"));
preOrderList.add(new GenericTreeNode<String>("C"));
preOrderList.add(new GenericTreeNode<String>("D"));
// Instead of checking equalities on the lists themselves, we can check equality on the toString's
// they should generate the same toString's
assertEquals(tree.build(GenericTreeTraversalOrderEnum.PRE_ORDER).toString(), preOrderList.toString());
}
//Post-order traversal will give us B D C A
@Test
void TestPostOrderBuild() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
List<GenericTreeNode<String>> postOrderList = new ArrayList<GenericTreeNode<String>>();
postOrderList.add(new GenericTreeNode<String>("B"));
postOrderList.add(new GenericTreeNode<String>("D"));
postOrderList.add(new GenericTreeNode<String>("C"));
postOrderList.add(new GenericTreeNode<String>("A"));
// Instead of checking equalities on the lists themselves, we can check equality on the toString's
// they should generate the same toString's
assertEquals(tree.build(GenericTreeTraversalOrderEnum.POST_ORDER).toString(), postOrderList.toString());
}
//Pre-order traversal with depth will give us A:0, B:1, C:1, D:2
@Test
void TestPreOrderBuildWithDepth() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
Map<GenericTreeNode<String>, Integer> preOrderMapWithDepth = new LinkedHashMap<GenericTreeNode<String>, Integer>();
preOrderMapWithDepth.put(new GenericTreeNode<String>("A"), 0);
preOrderMapWithDepth.put(new GenericTreeNode<String>("B"), 1);
preOrderMapWithDepth.put(new GenericTreeNode<String>("C"), 1);
preOrderMapWithDepth.put(new GenericTreeNode<String>("D"), 2);
// Instead of checking equalities on the maps themselves, we can check equality on the toString's
// they should generate the same toString's
assertEquals(tree.buildWithDepth(GenericTreeTraversalOrderEnum.PRE_ORDER).toString(), preOrderMapWithDepth.toString());
}
//Post-order traversal with depth will give us B:1, D:2, C:1, A:0
@Test
void TestPostOrderBuildWithDepth() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
Map<GenericTreeNode<String>, Integer> postOrderMapWithDepth = new LinkedHashMap<GenericTreeNode<String>, Integer>();
postOrderMapWithDepth.put(new GenericTreeNode<String>("B"), 1);
postOrderMapWithDepth.put(new GenericTreeNode<String>("D"), 2);
postOrderMapWithDepth.put(new GenericTreeNode<String>("C"), 1);
postOrderMapWithDepth.put(new GenericTreeNode<String>("A"), 0);
// Instead of checking equalities on the maps themselves, we can check equality on the toString's
// they should generate the same toString's
assertEquals(tree.buildWithDepth(GenericTreeTraversalOrderEnum.POST_ORDER).toString(), postOrderMapWithDepth.toString());
}
//toString and toStringWithDepth both use pre-order traversal
@Test
void TestToString() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
List<GenericTreeNode<String>> preOrderList = new ArrayList<GenericTreeNode<String>>();
preOrderList.add(new GenericTreeNode<String>("A"));
preOrderList.add(new GenericTreeNode<String>("B"));
preOrderList.add(new GenericTreeNode<String>("C"));
preOrderList.add(new GenericTreeNode<String>("D"));
assertEquals(tree.toString(), preOrderList.toString());
}
@Test
void TestToStringWithDepth() {
GenericTree<String> tree = new GenericTree<String>();
GenericTreeNode<String> rootA = new GenericTreeNode<String>("A");
GenericTreeNode<String> childB = new GenericTreeNode<String>("B");
GenericTreeNode<String> childC = new GenericTreeNode<String>("C");
GenericTreeNode<String> childD = new GenericTreeNode<String>("D");
childC.addChild(childD);
rootA.addChild(childB);
rootA.addChild(childC);
tree.setRoot(rootA);
Map<GenericTreeNode<String>, Integer> preOrderMapWithDepth = new LinkedHashMap<GenericTreeNode<String>, Integer>();
preOrderMapWithDepth.put(new GenericTreeNode<String>("A"), 0);
preOrderMapWithDepth.put(new GenericTreeNode<String>("B"), 1);
preOrderMapWithDepth.put(new GenericTreeNode<String>("C"), 1);
preOrderMapWithDepth.put(new GenericTreeNode<String>("D"), 2);
assertEquals(tree.toStringWithDepth(), preOrderMapWithDepth.toString());
}
}
That’s pretty much it. Hope you found this useful!
Sign in to leave a comment.
Loading…