Esercizio 9foglia più profonda di un albero binario proprio
In questa pagina 6
Testo (esempio di tema d'esame e scritto del 09/09/2025, seconda parte, esercizio 1, 5 punti). Si vuole progettare un algoritmo ricorsivo deepLeaf per trovare la foglia più profonda in un albero binario proprio . Detta deepLeaf(T, v) la generica invocazione su un nodo , per risolvere il problema si eseguirà deepLeaf(T, T.root()) (che può anche restituire informazioni aggiuntive). Si ricordi che in ogni sottoalbero la profondità (in ) della sua foglia più profonda è pari all'altezza di .
(a) Descrivere deepLeaf(T, v) tramite pseudocodice, specificandone con attenzione l'input e l'output.
(b) Analizzare la complessità di deepLeaf(T, T.root()) in funzione del numero di nodi in .
Idea
Il suggerimento del testo: l'altezza di è la massima profondità delle sue foglie (vedi AlberiAlbero radicato (definizione per padre e ricorsiva), terminologia (antenati, discendenti, nodi interni ed esterni, sottoalbero, albero ordinato), profondità, livello, altezza; altezza = massima profondità delle foglie; algoritmi depth e height con costo; somma dei figli = n-1; esempio di algoritmo Omega(n^2) (heightBad).Alberi →). Quindi la foglia più profonda di è, tra le foglie più profonde dei due sottoalberi figli, quella del sottoalbero più alto. Per decidere serve conoscere l'altezza dei due figli: si restituisce una coppia (foglia, altezza), come in heightSum (vedi Alberi binariAlbero binario e albero binario proprio; interfaccia; relazioni tra nodi, foglie e altezza (m = n-m+1, h+1 <= m <= 2^h, 2h+1 <= n <= 2^(h+1)-1) con dimostrazioni; visita inorder; parse tree e valutazione di espressioni; heightSum come esempio di calcolo di un'informazione più ricca.Alberi binari →): conviene calcolare un'informazione più ricca di quella richiesta. È una visita in postorder.
(a) Pseudocodice
Algoritmo deepLeaf(T, v)
Input: albero binario proprio T, nodo v di T
Output: coppia (w, h) con w = una foglia più profonda di T_v e h = altezza di T_v
if T.isExternal(v) then return (v, 0)
(wL, hL) <- deepLeaf(T, T.left(v))
(wR, hR) <- deepLeaf(T, T.right(v))
if hL > hR then return (wL, hL + 1)
else return (wR, hR + 1)Chiamata: (w, h) <- deepLeaf(T, T.root()); è la foglia cercata e l'altezza dell'albero.
Correttezza (induzione sull'altezza). Foglia: l'unica foglia di è stesso, a profondità = altezza. Nodo interno: le foglie di sono quelle di e con profondità aumentata di rispetto ai sottoalberi; per ipotesi e sono le più profonde nei rispettivi sottoalberi, quindi la più profonda di è quella con altezza maggiore, a profondità in , che è l'altezza di .
(b) Complessità
L'albero della ricorsione ha esattamente un nodo per ogni nodo di ; ogni chiamata, escluse le figlie, fa un numero costante di operazioni (un test, un confronto, una coppia restituita). Dunque come una visita in postorder in cui la visita di un nodo costa .
Esempio
Albero: radice con figli e ; ha figli (foglie) e ; è foglia. deepLeaf(a) , deepLeaf(b) ; in : , quindi si restituisce (con la parità si sceglie il destro; si poteva scegliere , che è ugualmente profonda). deepLeaf(y) . In : , quindi : la foglia più profonda è , a profondità . (Controllato su 500 alberi casuali: profondità della foglia restituita = massima profondità.)
Alternative (peggiori)
- Calcolare la profondità di ogni foglia con
depth(risalendo dalla foglia) e scegliere la massima: corretto, ma ognidepthcosta e nel caso peggiore il totale è (vediheightBadin AlberiAlbero radicato (definizione per padre e ricorsiva), terminologia (antenati, discendenti, nodi interni ed esterni, sottoalbero, albero ordinato), profondità, livello, altezza; altezza = massima profondità delle foglie; algoritmi depth e height con costo; somma dei figli = n-1; esempio di algoritmo Omega(n^2) (heightBad).Alberi →). - Memorizzare in ogni nodo un campo
v.heighte poi cercare la foglia: due visite, ancora ma più codice.
Errori comuni
- Restituire solo la foglia: senza l'altezza il padre non può confrontare i due figli, e si finisce a ricalcolare le altezze (quadratico).
- Restituire solo l'altezza: si risponde a un problema diverso.
- Scrivere
hL >= hRehL > hRindifferentemente ma non indicare cosa succede alla parità: il testo accetta una qualsiasi delle foglie più profonde, va però dichiarato.
Versione ripasso
Testo. Albero binario proprio : algoritmo ricorsivo deepLeaf(T, v) che trova la foglia più profonda; specificare input e output; complessità in .
- Idea: altezza di = massima profondità delle foglie (vedi AlberiAlbero radicato (definizione per padre e ricorsiva), terminologia (antenati, discendenti, nodi interni ed esterni, sottoalbero, albero ordinato), profondità, livello, altezza; altezza = massima profondità delle foglie; algoritmi depth e height con costo; somma dei figli = n-1; esempio di algoritmo Omega(n^2) (heightBad).Alberi →) ⇒ la foglia più profonda di è quella del figlio con altezza maggiore; si restituisce la coppia (foglia, altezza): postorder.
- Pseudocodice: foglia ⇒ ; altrimenti , dai figli; se restituisce , altrimenti .
- Complessità: una chiamata per nodo, costo costante: (vedi Alberi binariAlbero binario e albero binario proprio; interfaccia; relazioni tra nodi, foglie e altezza (m = n-m+1, h+1 <= m <= 2^h, 2h+1 <= n <= 2^(h+1)-1) con dimostrazioni; visita inorder; parse tree e valutazione di espressioni; heightSum come esempio di calcolo di un'informazione più ricca.Alberi binari →).
- Alternativa lenta:
depthda ogni foglia, . - Esempio: radice con figli (foglie , ) e (foglia): , , in ⇒ . Sulla parità si sceglie una foglia qualsiasi purché sia dichiarato.
- Correttezza (induzione sull'altezza): le foglie di hanno profondità quella nel sottoalbero; la più profonda sta nel figlio più alto.
- Errori: restituire solo la foglia (o solo l'altezza); parità non dichiarata.