你不必考虑所有的嵌套。你只需要考虑你在哪里(例如,节点列表中的上一个条目是什么级别)以及下一个条目在哪里。
在这种情况下,解决方案在于读取树的方式。请注意,在作为树输入源的节点列表中,紧跟在父节点之后,下一个节点是子节点。如果某个节点之后的节点不是该节点的子节点(即,如果它的级别不是低一级),则它是前一个节点的祖先之一的子节点。
所以:
- 如果第 n 行的级别等于 1 加上第 n-1 行的级别,则第 n 行包含第 n-1 行的子节点。
- 否则,从第 n-1 行的节点向上走,直到找到一个比第 n 行的级别低一级的节点。该祖先节点是第 n 行节点的父节点。
您也不必递归地执行此操作。
currLevel = 0;
currNode = root;
do {
node = read();
if (somethingRead()) {
// If this one is one level below the last one, it goes in as a child and we're done
if (node.level == currNode.level + 1) {
currNode.addChild(node);
currNode = node;
} else {
// Otherwise this one has to be at a level above this node's child, so back up
while (node.level >= currNode.level) {
currNode = currNode.parent(); // check for root left out here ...
}
if (node.level == currNode.level + 1) {
currNode.addChild(node);
currNode = node;
} else {
// handle illegal condition in list
}
}
}
} while (moreNodesToRead());
对您的解决方案的回应
您的解决方案反映了您不愿意使用假节点作为树的根。这是一个可以做出的设计选择。这是我的版本。
我有点担心您如何处理被弄乱的传入数据
- 呈现的节点比其前一层多一层。
- 显示的第一个节点不在级别 1。
- 节点的级别为 0 或更低(不检查以下内容)
另外,我建议您允许currNode
在null
当前节点应该是根时。从理论上讲,它可能发生在while
备份当前节点的循环中,但请注意,在代码中的这一点上,您已经知道新节点的级别高于 1,因此currNode
永远不应备份超过级别 1 的节点。如果该假设是错误的,让它生成 NPE 是合理的。
我建议进行以下更改:
Node currNode = null;
List<Root> roots = new ArrayList<Root>();
do {
Node node = generateNode(nodesList.next());
if (node.getLevel() == 1) { //implies root level node
roots.add(node);
currNode = node;
} else if (currNode == null) {
// ... handle misformed input ... first node isn't level 1, ignore it
} else if (node.getLevel() == currNode.getLevel() + 1) {
currNode.childrenList.addChild(node);
node.setParent(currNode);
currNode = node;
} else {
Node savedCurrNode = currNode;
while (node.getLevel() <= currNode.getLevel()) {
currNode = currNode.getParent();
}
if (node.getLevel() == currNode.getLevel() + 1) {
currNode.childrenList.addChild(node);
node.setParent(currNode);
currNode = node;
} else {
// ... handle misformed input ... node level > last node level + 1, ignore it
currNode = savedCurrNode;
}
} while (hasMoreNodes(nodesList));
印刷
我对其进行了一些重新排列并更改了一些名称和职责(在评论中列出)。只是从上面详细说明一点,如果根只是一个节点,则根本不需要'printRoots()'方法。只需在级别设置为 0 的假根节点上调用“printChildren()”即可。但它会在顶部多打印一行。
(如果您缩进输出,它总是更容易阅读。)
警告:未经测试。
/** Print all the root nodes, each with any children it may have */
private void printRoots(List<Node> roots) {
for (int j = 0; j < roots.size(); j++) {
Node node = roots.get(j);
printContents(node, 1);
}
}
/** Print one node and any children it might have */
private void printContents(Node node, int level) {
for (int i=1 ; i < level ; ++i) {
print(" ");
}
print(node.toString());
println();
printChildren(node, level+1);
}
/** Print each child of the supplied node. Notice how this is just like getting the
* list of children and calling 'printRoots()'
*//
private void printChildren(Node node, int level) {
for (int i = 0; i < node.getChildrenList().size(); i++) {
Node childNode = node.getChildrenList().get(i);
printContents(childNode, level);
}
}