2012-10-12 15 views
21

Come si può scrivere un iteratore Java (cioè bisogno della next e hasNext metodi) che prende la radice di un albero binario e scorre attraverso i nodi dell'albero binario in in ordine moda ?In ordine iteratore per albero binario

+0

Penso che la domanda sia abbastanza chiara, se si sa cos'è un albero binario e si ha esperienza nell'analizzarle. – ilomambo

+0

Penso che sia la vera domanda, va bene. Probabilmente avrebbe dovuto essere invece chiuso come troppo ampio. –

risposta

36

Il primo elemento di un sottostruttura è sempre il più a sinistra. L'elemento successivo dopo un elemento è il primo elemento della sottostruttura di destra. Se l'elemento non ha un figlio destro, l'elemento successivo è il primo antenato di destra dell'elemento. Se l'elemento non ha né un figlio destro né un antenato destro, è l'elemento più a destra ed è l'ultimo in iterazione.

Spero che il mio codice sia leggibile dall'uomo e copra tutti i casi.

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

Si consideri il seguente albero:

 d 
/ \ 
    b  f 
/\ /\ 
a c e g 
  • Il primo elemento è "completamente a sinistra dalla radice"
  • a non hai figlio destro, quindi l'elemento successivo è "up fino a quando non vieni da sinistra "
  • b ha un figlio destro, quindi itera la sottostruttura di destra
  • c non ha un figlio giusto. È genitore è b, che è stato attraversato. Il prossimo genitore è d, che non è stato attraversato, quindi fermati qui.
  • d ha una sottostruttura giusta. Il suo elemento più a sinistra è e.
  • ...
  • g non ha sottostruttura di destra, quindi camminare. f è stato visitato, poiché siamo venuti da destra. d è stato visitato. d non ha genitore, quindi non possiamo andare oltre. Siamo arrivati ​​dal nodo più a destra e abbiamo finito di ripetere.
+1

C'era una ragione per cui non ho inserito un iteratore valido nella mia risposta, ed era così che l'OP avrebbe dovuto farlo da sé. Dare risposte come queste non giova a nessuno. –

+1

@HunterMcMillen buon punto. Howerer, questa non è comunque una copia e incolla. Almeno una riga deve essere cambiata ;-) ma confesso che non è stata deliberata. Il mio obiettivo era la leggibilità, non la correttezza. Non l'ho nemmeno provato ;-) –

+0

Adoro la tua idea di archiviare il prossimo. Potevo solo pensare di memorizzare il nodo corrente, non il prossimo, e stavo avendo così tanti problemi a trovare un modo per stampare il primo elemento. Grazie. – Variadicism

0

E 'piuttosto semplice, per l'attraversamento in ordine di visitare il figlio sinistro se ce n'è uno, quindi il nodo radice, allora il bambino a destra:

visit_node(node) 
    if node.left: visit_node(node.left) 
    // visit the root node 
    if node.right: visit_node(node.right) 

Diagramma:

 a 
/ \  (in-order traversal would give bac) 
    b  c 
+6

Ma quando si scrive un iteratore (ad esempio un iteratore Java che richiede i metodi 'next' e' hasNext'), come si può incorporare un metodo ricorsivo come quello? –

+0

@PaulSeangwongree: puoi sempre prendere i nodi in ordine e aggiungerli a qualche altra raccolta. –

2

Per ottenere la voce successiva, 'nextEntry()', per l'iteratore, ho guardato i frammenti da java.util.TreeMap incollati di seguito. In parole povere, direi che assicuri che il nodo radice non sia nullo, altrimenti restituisca null. Se non lo è, consulta il nodo giusto se non è nullo. Quindi visita la sinistra (se non è nullo) e visita quella sinistra ripetutamente in un ciclo while fino a colpire null. Se il nodo destro originale è nullo, invece di tutto ciò, visitare il nodo genitore se non è nullo. Ora inserisci un ciclo while in cui visiti il ​​genitore finché non è nullo o il nodo che stai visitando ha il nodo destro (figlio) uguale alla tua ultima posizione. Ora restituisci qualunque voce tu stia visitando. In mancanza di tutte queste opzioni, restituisce il nodo root (originale). 'HasNext()' si limita a verificare se questa "voce successiva" che si sta restituendo è nullo o no.

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

Sì, l'ho fatto. Per favore pubblica il tuo e potrebbe essere la risposta accettata se uguale o migliore alla mia spiegazione. In realtà afferma nel file TreeMap.java compresso con il jdk che il codice è properietary. Se questo è il caso, dirò che ~ 30 linee su 2400 sono fair use per scopi educativi. – apcris

+0

Ho pubblicato la mia risposta. –

+0

Non sono sicuro che la trascrizione aiuti a capire ... –

Problemi correlati