在每个级别具有多个子(已排序)的Java树结构

Ste*_*ins 9 java data-structures

我正在使用一个平面的对象列表,但它们在父子关系中相互关联.一个对象可以有任意数量的子节点,或者根本没有.我需要将这些对象显示为树,显示这些关系.树的每个级别应进行分类(对象兼容Collections.sort()).

问题分为两个部分:

  1. Java是否有一个很好的开箱即用的数据结构来保存这样一棵树,或者我是否需要从头开始编写一个?(这不是一个巨大的任务,但重新发明轮子是没有意义的)我DefaultTreeModel在Swing中知道...但是这个应用程序在服务器端运行,并且在代码审查中使用Swing包将不受欢迎.

  2. 将平面列表加载到这样的数据结构中的最佳模式是什么?我的第一个想法是识别根级对象,然后使用递归方法遍历他们的子孙,孙子等等.但是,为了在树中的每个级别对对等体进行排序的要求...我是当我正在构建树时,不确定是否更有意义地担心这一点,或者在我解析树以供显示时担心它.

Sea*_*oyd 9

这是一个快速而又脏的Tree实现,它在所有级别上使用TreeSet(您可以提供比较器,或者使用自然顺序):

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

以下是一些针对它的示例代码:

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;
    }
});
Run Code Online (Sandbox Code Playgroud)

输出:

1
1> 2
1> 3
1> 3> 4


Pét*_*rök 4

将平面列表加载到此类数据结构中的最佳模式是什么?我的第一个想法是识别根级对象,然后使用递归方法向下遍历它们的子级、孙级等。

如果我理解正确的话,您只有一个平面列表,其元素之间没有任何具体关联,并且您可以以某种方式检测特定元素是否是另一个元素的子元素。

在这种情况下,您可以

  1. 对列表进行排序
  2. (如果还不知道根节点,则识别根节点)
  3. 将根放入队列
  4. 从队列中取出第一个节点
  5. 从链表的第一个元素开始,检查每个元素是否是当前节点的子节点;如果有,则添加到树的当前层并放入队列
  6. 从步骤 4 开始重复。

如果检测父子关系的成本很高,您可以通过为已识别树中位置的每个节点存储/清零标志来提高性能,以便在遍历列表时可以跳过它们。或者,您可以将整个排序列表复制到链接列表中,这样就可以轻松地从中删除已处理的元素。