我的任务是列出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()方法中如何工作的问题。任何帮助,将不胜感激。非常感谢。
答案 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);
}