使用对象列表构建树

时间:2018-06-20 22:52:03

标签: java tree

我的任务是列出5本书的清单,每本书包含一个标题和一个等级,然后将它们变成一棵看起来像这样的树:

    //1 1984
    //  2 Animal Farm
    //      3 Crime and Punishment
    //      3 Demons
    //  2 War and Peace

在分级树结构方面,较低的评级优先。

我上了一堂课,叫书:

public static class Book {
    protected int rating;
    protected String title;

    public Book (int rating, String title) {
        this.rating = rating;
        this.title = title;
    }
}

然后我制作了一个Node类,它将组成树:

public static class Node {
    protected Book book;
    protected List<Node> children;

    public Node(Book book) {
        this.book = book;
        this.children = new ArrayList<>();
    }   
}

然后我的主要方法如下:

    public static void main (String[]args) throws Exception {
    BufferedReader br = new BufferedReader (new InputStreamReader(System.in));
    List<Book> books = new ArrayList<>();
    books.add(new Book(1,"1984"));
    books.add(new Book (2,"Animal Farm"));
    books.add(new Book (3,"Crime and Punishment"));
    books.add(new Book (2,"War and Peace"));
    books.add(new Book (3,"Demons"));

    Node node = createTree(books);

}

最后,这是我遇到最多问题的地方,正在构建实际的树。它可以只包含打印语句,但是我对解决此问题的最佳方法感到困惑:

    public static Node createTree(List<Book>books) {

    Node root = new Node (books.get(0));
    root.children.add(root);

    //The first node will be 1984 with a 1 rating. After that I'm not sure what exactly to do next?


    return root;

}

我知道似乎我只是在寻找答案,但我实际上整天都在构建此东西,尝试了所有事情,并且陷入了僵局。我知道该解决方案可能可以递归地解决,但是我很难解决它再次在createTree()方法中如何工作的问题。任何帮助,将不胜感激。非常感谢。

3 个答案:

答案 0 :(得分:1)

我对具有2个以上节点的树结构有些不熟悉。我在想一个Min-Heap-一个完整的二叉树,其中每个内部节点中的值 小于或等于该节点的子代中的值-可以通过操纵树遍历的处理方式来完成同一件事。

在任何情况下,假设树上可以有2片以上的叶子,则以下解决方案应为您提供帮助:


除了root如果为null之外,add方法还需要处理3种主要情况:

案例1 :图书评级小于当前节点评级,将新节点追加到当前节点的位置,然后将当前节点作为叶添加到新节点。 / p>

案例2 :图书评分大于当前节点评分。检查该节点是否有叶子,如果没有叶子,则将该书作为叶子添加到当前节点并返回。如果有叶子,我们输入第一个叶子作为参数,然后再次调用add方法(递归)。

案例3 :图书评分等于当前节点评分。首先,如果访问的节点是树的根,则将新节点作为叶添加到索引为0的树中。遍历根节点的所有叶,并将所有不等于书评的叶作为叶添加到新节点。其次,如果不是根节点,则获取当前节点的父节点,然后将新节点作为叶添加到该节点。


请注意,每当需要重新平衡树时,叶子都会附加到第一片叶子(leaves.get(0))的叶子上。其次,第一片叶子是子树的主要所有者。

toString方法使用预排序迭代,并跟踪打印树的深度。

public class Tree {

    private static class Node {
        Book book;
        List<Node> leaves;
        Node parent;

        public Node(Book b, Node p) {
            this.book = b;
            this.leaves = new LinkedList<>();
            this.parent = p;
        }

        @Override
        public String toString() {
            return book.toString();
        }

    }

    private Node root;

    private void swap(Node oldParent, Node newParent) {
        oldParent.leaves.add(newParent);
        newParent.parent = oldParent.parent;
        oldParent.parent = newParent;
        newParent.leaves.add(oldParent);
        oldParent.leaves.remove(newParent);
        if (newParent.parent != null) {
            newParent.parent.leaves.add(0, newParent);
            newParent.parent.leaves.remove(oldParent);
        }
        if (oldParent == root) {
            root = newParent;
            // Handle special scenario when the leaf of the root and the leaf of the the leaf
            // have the same value and then rebalance the leaves.
            if (!oldParent.leaves.isEmpty() && !newParent.leaves.isEmpty()) {
                Node n2 = oldParent.leaves.get(0); 
                Node n1 = newParent.leaves.get(0);
                if (n1.book.rating != n2.book.rating)
                    return;
                root.leaves.add(0, n2);
                n2.parent = root;
                n1.leaves.clear();
            }
        }
    }


    private void add(Node n, Book b) {
        System.out.println("@" + b.toString());
        int prevNodeRating = n.book.rating;
        if (b.rating < prevNodeRating) {
            swap(n, new Node(b, n));
        }
        else if (b.rating > prevNodeRating) {
            if (n.leaves.isEmpty()) {
                Node newNode = new Node(b, n);
                n.leaves.add(newNode);    
            } else {
                add(n.leaves.get(0), b);
                return;
            }
        } 
        else {
            if (n == root) {
                if (!n.leaves.isEmpty() &&  n.leaves.get(0).book.rating == b.rating) {
                    root.leaves.add(new Node(b, n));
                    return;
                } 
                Node newNode = new Node(b, n);
                n.leaves.add(0, newNode);   // set at first position
                Iterator<Node> itr = n.leaves.iterator();
                itr.next(); // skip first;
                while (itr.hasNext()) {
                    Node leaf = itr.next();
                    if (leaf.book.rating >= b.rating) {
                        newNode.leaves.add(leaf);
                        leaf.parent = newNode;
                        itr.remove();
                    } 
                }
            } else {
                n.parent.leaves.add(new Node(b, n.parent));
            }
        }
        System.out.println(toString() + "\n----------------");
    }

    public void add(Book b) {
        if (root == null)
            root = new Node(b, null);
        else add(root, b);
    }

    private void toStringItr(Node n, int lvl, StringBuilder sb) {
        if(n == null) return;                    
        for (int i = 0; i < 3*lvl; i++) {
           sb.append(" ");
        }
        sb.append(n.book.toString()).append("\n");
        n.leaves.forEach((leaf) -> {
            toStringItr(leaf, lvl + 1, sb);
        });

    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (root == null)
            return "null";
        toStringItr(root, 0, sb);
        return sb.toString();
    }
}

输入

Tree mt = new Tree();
mt.add(new Book(4,"A"));
mt.add(new Book(3,"B"));
mt.add(new Book(2,"C"));
mt.add(new Book(3,"D"));
mt.add(new Book(1,"E"));
mt.add(new Book(4,"F"));
mt.add(new Book(1,"G"));
mt.add(new Book(2,"H"));
mt.add(new Book(8,"X"));
mt.add(new Book(7,"Y"));
System.out.println(mt.toString());

输出

1, E
   1, G
      2, C
         3, B
            4, A
               7, Y
                  8, X
            4, F
         3, D
      2, H

或者,

1, 1984
   2, Animal Farm
      3, Crime and Punishment
      3, Demons
   2, War and Peace

逐步输出(在第一个根目录之后)

@3, B
3, B
   4, A

----------------
@2, C
2, C
   3, B
      4, A

----------------
@3, D
@3, D
2, C
   3, B
      4, A
   3, D

----------------
@1, E
1, E
   2, C
      3, B
         4, A
      3, D

----------------
@4, F
@4, F
@4, F
@4, F
1, E
   2, C
      3, B
         4, A
         4, F
      3, D

----------------
@1, G
1, E
   1, G
      2, C
         3, B
            4, A
            4, F
         3, D

----------------
@2, H
@2, H
@2, H
1, E
   1, G
      2, C
         3, B
            4, A
            4, F
         3, D
      2, H

----------------
@8, X
@8, X
@8, X
@8, X
@8, X
1, E
   1, G
      2, C
         3, B
            4, A
               8, X
            4, F
         3, D
      2, H

----------------
@7, Y
@7, Y
@7, Y
@7, Y
@7, Y
@7, Y
1, E
   1, G
      2, C
         3, B
            4, A
               7, Y
                  8, X
            4, F
         3, D
      2, H

----------------

答案 1 :(得分:1)

一个开始是这样的:

public static Node createTree(List<Book> books) {
    Node tree = null;
    ...
    return tree;
}

一个人会怎么做?

假设最后插入的节点是一个等级为4的节点:

/-->1-->3-->*4*

如果评分不大于3,例如2,则提高到小于2。

/-->1-->*+2*               going up 2 nodes, inserting 2
/-->1-->3-->*+4*           going up 1 node, inserting 4
/-->1-->3-->4-->*+6*       inserting 6

如您所见,一个人需要一个 stack 节点,这些节点代表从根开始的最后一条路径。

使用伪代码:

for (Book book : books) {
    while (!path.isEmpty()
            && book.rating >= path.last().book.rating) {
        path.removeLast();
    }
    Node node = new Node(book);
    if (path.isEmpty()) {
        tree = node;
    } else {
        path.last().children.add(node);
    }
    path.add(node);
}

您必须考虑根:一棵树只能有一个根,一个等级为1。或者您制作的人造(预定义)根的等级为0,因此可以有多个等级1。

答案 2 :(得分:1)

对于此特定示例,这是一种生成所需树的非常简单的方法:

private static Node createTree(List<Book> books) {
    Node root = new Node(null);
    addTrees(root, books, 1);
    return root;
}

private static void addTrees(Node node, List<Book> books, int rating) {
    int i = 0;
    while (i < books.size()) {
        Book book = books.get(i);
        if (book.rating == rating) {
            node.children.add(new Node(book));
            books.remove(i);
        } else {
            ++i;
        }
    }
    if (!node.children.isEmpty()) {
        addTrees(node.children.get(0), books, rating+1);
    }
}

然后使用方法打印树:

private static void printTree(Node node) {
    if (node.book != null) {
        printBook(node.book);
    }
    for (Node child: node.children) {
        printTree(child);
    }
}

private static void printBook(Book book) {
    for (int i = 1; i < book.rating; ++i) {
        System.out.print("    ");
    }
    System.out.println(book.rating + " " + book.title);
}