Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java tree structure with multiple children (sorted) at each level

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:

  1. 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.

  2. 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.

like image 663
Steve Perkins Avatar asked Jan 20 '11 15:01

Steve Perkins


People also ask

Can tree have more than 2 child?

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.

Can a tree have more than 2 child nodes?

Every node can have multiple child nodes. The number of child nodes can vary from one node to the other.

Is there a tree data structure in Java?

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.

How to create a tree structure Java?

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).


3 Answers

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

like image 178
Sean Patrick Floyd Avatar answered Nov 15 '22 17:11

Sean Patrick Floyd


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

  1. sort the list
  2. (identify the root node, if it is not known yet)
  3. put the root into a queue
  4. take the first node from the queue
  5. starting from the first element of the list, check each element whether it is a child of the current node; if so, add it to the current level of the tree and put it into the queue
  6. repeat from step 4.

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.

like image 41
Péter Török Avatar answered Nov 15 '22 15:11

Péter Török


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

like image 44
Navi Avatar answered Nov 15 '22 16:11

Navi