it-swarm.com.de

In-Order-Iterator für Binärbaum

Wie kann ich einen Java Iterator (dh benötigt die Methoden next und hasNext) schreiben, der die Wurzel eines Binärbaums zieht und durch die Knoten der Binärbaum in in-order Mode?

24
Paul S.

Das erste Element eines Teilbaums ist immer das am weitesten links stehende. Das nächste Element nach einem Element ist das erste Element seines rechten Unterbaums. Wenn das Element kein rechtes Kind hat, ist das nächste Element der erste rechte Vorfahr des Elements. Wenn das Element weder ein rechtes Kind noch einen rechten Vorfahren hat, ist es das Element ganz rechts und es ist das letzte in der Iteration.

Ich hoffe, mein Code ist für Menschen lesbar und deckt alle Fälle ab.

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;
        }
     }
 }

Betrachten Sie den folgenden Baum:

     d
   /   \
  b     f
 / \   / \
a   c e   g
  • Das erste Element ist "vollständig von der Wurzel verlassen"
  • a hat kein rechtes Kind, also ist das nächste Element "bis du von links kommst"
  • b hat ein rechtes Kind, also iteriere den rechten Teilbaum von b
  • c hat kein rechtes Kind. Das übergeordnete Element ist b, das durchlaufen wurde. Das nächste übergeordnete Element ist d, das noch nicht durchlaufen wurde. Hören Sie also hier auf.
  • d hat einen rechten Teilbaum. Das am weitesten links stehende Element ist e.
  • ...
  • g hat keinen richtigen Teilbaum. f wurde besucht, da wir von rechts gekommen sind. d wurde besucht. d hat keine übergeordneten Elemente, daher können wir nicht weiter nach oben gehen. Wir sind vom Knoten ganz rechts gekommen und haben die Iteration abgeschlossen.
39
John Dvorak

Um den nächsten Eintrag 'nextEntry ()' für den Iterator zu erhalten, habe ich mir Ausschnitte aus Java.util.TreeMap unten eingefügt. Im Klartext würde ich sagen, dass Sie sicherstellen, dass der Wurzelknoten nicht null ist, sonst geben Sie null zurück. Ist dies nicht der Fall, wählen Sie den richtigen Knoten aus, wenn er nicht null ist. Besuchen Sie dann die linke Seite (wenn nicht null) und besuchen Sie die linke Seite wiederholt in einer while-Schleife, bis Sie null treffen. Wenn der ursprüngliche rechte Knoten null ist, besuchen Sie stattdessen den übergeordneten Knoten, wenn dieser nicht null ist. Geben Sie nun eine while-Schleife ein, in der Sie den übergeordneten Knoten sehen, bis er entweder null ist oder der Knoten, den Sie gerade besuchen, über den rechten (untergeordneten) Knoten verfügt, der Ihrer letzten Position entspricht. Geben Sie nun den Eintrag zurück, auf dem Sie gerade sitzen. Wenn alle diese Optionen fehlschlagen, geben Sie den (ursprünglichen) Stammknoten zurück. 'HasNext ()' prüft lediglich, ob dieser "nächste Eintrag", den Sie zurückgeben, null ist oder nicht.

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;
    }
}
2
apcris