web-dev-qa-db-fra.com

Itérateur en ordre pour l'arbre binaire

Comment puis-je écrire un Java itérateur (c'est-à-dire a besoin des méthodes next et hasNext) qui prend la racine d'un arbre binaire et itère à travers les nœuds du arbre binaire en dans l'ordre mode?

24
Paul S.

Le premier élément d'un sous-arbre est toujours le plus à gauche. L'élément suivant après un élément est le premier élément de son sous-arbre droit. Si l'élément n'a pas de droit enfant, l'élément suivant est le premier ancêtre droit de l'élément. Si l'élément n'a ni enfant ni ancêtre correct, il s'agit de l'élément le plus à droite et il est le dernier de l'itération.

J'espère que mon code est lisible par l'homme et couvre tous les cas.

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

Considérez l'arbre suivant:

     d
   /   \
  b     f
 / \   / \
a   c e   g
  • Le premier élément est "complètement à gauche de la racine"
  • a n'a pas d'enfant à droite, donc l'élément suivant est "jusqu'à ce que vous veniez de gauche"
  • b a un enfant droit, alors itérez le sous-arbre droit de b
  • c n'a pas d'enfant à droite. Son parent est b, qui a été traversé. Le parent suivant est d, qui n'a pas été traversé, alors arrêtez-vous ici.
  • d a un sous-arbre droit. Son élément le plus à gauche est e.
  • ...
  • g n'a pas de sous-arbre droit, alors montez. f a été visité, car nous venons de droite. d a été visité. d n'a pas de parent, nous ne pouvons donc pas avancer plus haut. Nous venons du nœud le plus à droite et nous avons terminé l'itération.
39
John Dvorak

Pour obtenir l'entrée suivante, 'nextEntry ()', pour l'itérateur, j'ai regardé des extraits de Java.util.TreeMap collé ci-dessous. En clair, je dirais que vous vous assurez que le nœud racine n'est pas nul en premier sinon retournez null. Si ce n'est pas le cas, visitez le nœud de droite s'il n'est pas nul. Ensuite, visitez la gauche (sinon nulle) et visitez celle de gauche à plusieurs reprises dans une boucle de temps jusqu'à atteindre null. Si le nœud droit d'origine est nul, au lieu de tout cela, visitez le nœud parent s'il n'est pas nul. Entrez maintenant une boucle while où vous visitez le parent jusqu'à ce qu'il soit nul ou que le nœud que vous visitez actuellement ait son nœud droit (enfant) égal à votre dernière position. Maintenant, retournez l'entrée sur laquelle vous vous situez. A défaut de toutes ces options, renvoyez le nœud racine (d'origine). 'HasNext ()' vérifie simplement si cette "prochaine entrée" que vous retournez est nulle ou non.

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