すべてのネスティングについて考える必要はありません。自分がどこにいるのか (ノード リストの前のエントリがどのレベルであったか) と、次のエントリがどこにあるのかを考えるだけで済みます。
この場合、解決策はツリーが読み込まれる方法にあります。ツリーの入力ソースであるノードのリストで、親ノードの直後にある次のノードが子であることに注意してください。あるノードの後のノードがそのノードの子でない場合 (つまり、そのレベルが 1 つ下のレベルでない場合)、それは前のノードの祖先のいずれかの子です。
そう:
- 行 n のレベルが行 n-1 のレベルに 1 を加えた値に等しい場合、行 n は行 n-1 の子を保持します。
- それ以外の場合は、行 n-1 のノードから、行 n のレベルよりもレベルが 1 低いノードが見つかるまで、ツリーを上に移動します。その祖先ノードは、行 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 レベル以上上のノードが表示されます。
- 提示された最初のノードはレベル 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()」を呼び出すだけです。ただし、上部に余分な行が 1 行出力されます。
(出力をインデントすると常に読みやすくなります。)
警告: テストされていません。
/** 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);
}
}