バイナリ ツリーのルートを取得し、バイナリ ツリーのノードを順番next
に繰り返す Java イテレータ (つまりandメソッドが必要) を作成するにはどうすればよいですか?hasNext
3 に答える
サブツリーの最初の要素は常に左端の要素です。要素の次の要素は、その右側のサブツリーの最初の要素です。要素に適切な子がない場合、次の要素は要素の最初の適切な祖先です。要素に適切な子も適切な祖先もない場合、それは右端の要素であり、反復の最後になります。
私のコードが人間が読める形式であり、すべてのケースをカバーしていることを願っています。
public class TreeIterator {
private Node next;
public TreeIterator(Node root) {
next = root;
if(next == null)
return;
while (next.left != null)
next = next.left;
}
public boolean hasNext(){
return next != null;
}
public Node next(){
if(!hasNext()) throw new NoSuchElementException();
Node r = next;
// If you can walk right, walk right, then fully left.
// otherwise, walk up until you come from left.
if(next.right != null) {
next = next.right;
while (next.left != null)
next = next.left;
return r;
}
while(true) {
if(next.parent == null) {
next = null;
return r;
}
if(next.parent.left == next) {
next = next.parent;
return r;
}
next = next.parent;
}
}
}
次のツリーについて考えてみます。
d
/ \
b f
/ \ / \
a c e g
- 最初の要素は「ルートから完全に離れている」
a
右の子がいないので、次の要素は「左から来るまで」です。b
正しい子がありますので、b
の正しいサブツリーを繰り返しますc
正しい子供がいません。親はb
、トラバースされたです。次の親はd
、トラバースされていないので、ここで停止します。d
正しいサブツリーがあります。その左端の要素はe
です。- ..。
g
正しいサブツリーがないので、上に歩いてください。f
私たちは右から来たので、訪問されました。d
訪問されました。d
親がいないので、それ以上上に移動することはできません。右端のノードから来て、反復が完了しました。
イテレータの次のエントリ'nextEntry()'を取得するために、java.util.TreeMap
以下に貼り付けたスニペットを確認しました。平易な英語では、最初にルートノードがnullでないことを確認してください。そうでない場合は、nullを返します。そうでない場合は、nullでない場合は右側のノードをビストします。次に、左側(nullでない場合)にアクセスし、nullに達するまでwhileループでその左側に繰り返しアクセスします。元の右ノードがnullの場合、それがnullでない場合は、そのすべてではなく、親ノードにアクセスします。次に、親がnullになるか、現在アクセスしているノードの右(子)ノードが最後の位置と等しくなるまで、親をビストするwhileループに入ります。次に、座っているエントリを返します。これらすべてのオプションが失敗した場合は、(元の)ルートノードを返します。'HasNext()'は、この「次のエントリ」かどうかをチェックするだけです
public final boolean hasNext() {
return next != null;
}
final TreeMap.Entry<K,V> nextEntry() {
TreeMap.Entry<K,V> e = next;
if (e == null || e.key == fenceKey)
throw new NoSuchElementException();
if (m.modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);
lastReturned = e;
return e;
}
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
順序通りのトラバーサルでは、左の子がある場合はそこにアクセスし、次にルート ノード、次に右の子にアクセスします。
visit_node(node)
if node.left: visit_node(node.left)
// visit the root node
if node.right: visit_node(node.right)
図:
a
/ \ (in-order traversal would give bac)
b c