I'm working with a flat List of objects, which nevertheless are associated with each other in parent-child relationships. An object may have any number of children, or none at all. I need to display these objects as a tree, showing those relationships. Each level of the tree should be sorted (the objects are compatible with Collections.sort()
).
The question is two-part:
Does Java have a good out-of-the-box data structure for holding such a tree, or do I need to write one from scratch? (not a huge task, but there's no sense in reinventing the wheel) I know about DefaultTreeModel
in Swing... but this application is running on the server-side, and use of the Swing package will get frowned upon in code review.
What would be the best pattern for loading a flat List into such a data-structure? My first thought is to identify the root-level objects, and then use a recursive method to traverse down through their children, grandchildren, etc. However, for the requirement of sorting the peers at each level in the tree... I'm not sure if it makes more sense to worry about this when I'm building the tree, or worry about it later when I'm parsing the tree for display.
A binary tree is a tree in which no node has more than two children, and every child is either a left child or a right child even if it is the only child its parent has. A full binary tree is one in which every internal node has two children.
Every node can have multiple child nodes. The number of child nodes can vary from one node to the other.
Tree data structure is useful on occasions where linear representation of data do not suffice, such as creating a family tree. Java provides two in-built classes, TreeSet and TreeMap, in Java Collection Framework that cater to the needs of the programmer to describe data elements in the aforesaid form.
To build a tree in Java, for example, we start with the root node. Node<String> root = new Node<>("root"); Once we have our root, we can add our first child node using addChild , which adds a child node and assigns it to a parent node. We refer to this process as insertion (adding nodes) and deletion (removing nodes).
Here is a quick-and-dirty Tree implementation that uses TreeSets on all levels (you can supply a comparator, or natural ordering will be used):
public class Tree<T> {
private final Node<T> rootElement;
public void visitNodes(final NodeVisitor<T> visitor){
doVisit(rootElement, visitor);
}
private static <T> boolean doVisit(final Node<T> node,
final NodeVisitor<T> visitor){
boolean result = visitor.visit(node);
if(result){
for(final Node<T> subNode : node.children){
if(!doVisit(subNode, visitor)){
result = false;
break;
}
}
}
return result;
}
public interface NodeVisitor<T> {
boolean visit(Node<T> node);
}
public Node<T> getRootElement(){
return rootElement;
}
private static final class NodeComparator<T> implements Comparator<Node<T>>{
private final Comparator<T> wrapped;
@Override
public int compare(final Node<T> o1, final Node<T> o2){
return wrapped.compare(o1.value, o2.value);
}
public NodeComparator(final Comparator<T> wrappedComparator){
this.wrapped = wrappedComparator;
}
}
public static class Node<T> {
private final SortedSet<Node<T>> children;
private final Node<T> parent;
private T value;
private final Comparator<?> comparator;
@SuppressWarnings("unchecked")
Node(final T value, final Node<T> parent, final Comparator<?> comparator){
this.value = value;
this.parent = parent;
this.comparator = comparator;
children =
new TreeSet<Node<T>>(new NodeComparator<T>((Comparator<T>) comparator));
}
public List<Node<T>> getChildren(){
return new ArrayList<Node<T>>(children);
}
public Node<T> getParent(){
return parent;
}
public T getValue(){
return value;
}
public void setValue(final T value){
this.value = value;
}
public Node<T> addChild(final T value){
final Node<T> node = new Node<T>(value, this, comparator);
return children.add(node) ? node : null;
}
}
@SuppressWarnings("rawtypes")
private static final Comparator NATURAL_ORDER = new Comparator(){
@SuppressWarnings("unchecked")
@Override
public int compare(final Object o1, final Object o2){
return ((Comparable) o1).compareTo(o2);
}
};
private final Comparator<?> comparator;
public Tree(){
this(null, null);
}
public Tree(final Comparator<? super T> comparator){
this(comparator, null);
}
public Tree(final Comparator<? super T> comparator, final T rootValue){
this.comparator = comparator == null ? NATURAL_ORDER : comparator;
this.rootElement = new Node<T>(rootValue, null, this.comparator);
}
public Tree(final T rootValue){
this(null, rootValue);
}
}
Here is some sample code against it:
final Tree<Integer> tree = new Tree<Integer>();
final Node<Integer> rootNode = tree.getRootElement();
rootNode.setValue(1);
final Node<Integer> childNode = rootNode.addChild(2);
final Node<Integer> newChildNode = rootNode.addChild(3);
newChildNode.addChild(4);
tree.visitNodes(new NodeVisitor<Integer>(){
@Override
public boolean visit(final Node<Integer> node){
final StringBuilder sb = new StringBuilder();
Node<Integer> curr = node;
do{
if(sb.length() > 0){
sb.insert(0, " > ");
}
sb.insert(0, String.valueOf(curr.getValue()));
curr = curr.getParent();
} while(curr != null);
System.out.println(sb);
return true;
}
});
Output:
1
1 > 2
1 > 3
1 > 3 > 4
What would be the best pattern for loading a flat List into such a data-structure? My first thought is to identify the root-level objects, and then use a recursive method to traverse down through their children, grandchildren, etc.
If I understand correctly, you only have a flat list, without any concrete associations between its elements, and you can detect somehow whether a particular element is the child of another.
In this case, you could
If detecting parent-child relationship is costly, you could improve performance by storing a flag for / nulling out each node whose location within the tree is already identified, so that you can jump over them when traversing the list. Alternatively, you may copy the whole sorted list into a linked list so that it is trivial to remove processed elements from it.
There are no tree structures in Java, but there are sorted ones: TreeSet and TreeMap. See for some hints java data-structure to simulate a data tree
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With