Esercizio 10albero binario bilanciato
In questa pagina 5
Testo (scritto del 07/08/2026, seconda parte, esercizio 2, 6 punti). Sia dato un albero binario. Un albero si dice bilanciato se, per ogni nodo, le altezze dei sottoalberi sinistro e destro differiscono al più di . (Ad esempio, la radice con figli e , dove ha figli ed , è bilanciata; un albero in cui da scende per più livelli un solo ramo mentre l'altro è corto non lo è.) Progettare un algoritmo ricorsivo isBalanced(root) che restituisca true se l'albero è bilanciato e false altrimenti.
(a) Scrivere l'algoritmo in pseudocodice, esplicitando all'inizio i parametri di ingresso e i valori di uscita. (b) Determinare la complessità al caso pessimo esprimendola in notazione , ed eventualmente e giustificando adeguatamente il risultato.
Suggerimento del testo: una soluzione efficiente può calcolare e fornire in uscita, durante ogni visita ricorsiva, non solo se un sottoalbero è bilanciato, ma anche una seconda informazione utile al padre per verificare il bilanciamento dei suoi sottoalberi.
Idea
Per il nodo servono: (1) e bilanciati, (2) (il valore assoluto, Valore assoluto (modulo)Il valore assoluto è la distanza di un numero da zero: definizione, proprietà, disuguaglianza triangolare e disequazioni con i moduli.Valore assoluto (modulo) →, perché non si sa quale dei due sottoalberi sia più alto). Un albero bilanciato in questo senso ha altezza (è la condizione degli alberi AVL, citati in Alberi binari di ricercaAlbero binario di ricerca come albero binario proprio con entry nei nodi interni e foglie vuote; inorder crescente; TreeSearch; get, put e remove (due casi, con predecessore inorder) in Theta(h); altezza fino a n-1; esempi di inserimenti; alberi aumentati con campi size e max e algoritmi di conteggio e interrogazione in O(h).Alberi binari di ricerca →). L'altezza dei figli è l'informazione extra suggerita: se ogni chiamata la restituisce insieme al booleano, il padre non deve ricalcolarla. Si usa la convenzione: altezza di un sottoalbero vuoto , altezza di una foglia (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 →). È un postorder.
(a) Pseudocodice
Algoritmo isBalanced(T)
Input: albero binario T (eventualmente vuoto)
Output: true se T è bilanciato, false altrimenti
return check(T.root())[0]
Algoritmo check(v)
Input: nodo v oppure null (sottoalbero vuoto)
Output: coppia (balanced, height): balanced = T_v bilanciato; height = altezza di T_v
(se balanced = false il valore di height è irrilevante)
if v = null then return (true, -1)
(bL, hL) <- check(left(v))
if bL = false then return (false, 0)
(bR, hR) <- check(right(v))
if bR = false then return (false, 0)
if |hL - hR| > 1 then return (false, 0)
return (true, 1 + max(hL, hR))Il controllo anticipato (return (false, 0) appena un sottoalbero è sbilanciato) non cambia la complessità asintotica: la risposta false si propaga fino alla radice senza ulteriori calcoli.
Correttezza (induzione sull'altezza). Sottoalbero vuoto: bilanciato per definizione, altezza ✓. Nodo : per ipotesi induttiva check sui figli restituisce correttamente (bilanciato, altezza). è bilanciato se e solo se lo sono entrambi i figli e le altezze differiscono al più di , che è esattamente ciò che si controlla; l'altezza di è per definizione.
(b) Complessità
Ogni nodo (e ogni puntatore nullo) genera al più una chiamata di check: nodi più al più sottoalberi vuoti. Il costo locale di una chiamata (confronti, un valore assoluto, un massimo, assegnazioni) è , escluse le chiamate figlie. Quindi:
- Limite superiore: , perché il numero di chiamate è e ognuna è .
- Limite inferiore: se l'albero è bilanciato (nessuna uscita anticipata: si visitano tutti i nodi, ognuno una volta), quindi nel caso pessimo la complessità è . (Non si può fare meglio di : per dire che un albero è bilanciato bisogna guardare tutti i nodi.)
Confronto con la soluzione ingenua (calcolare height ad ogni nodo e poi chiamarsi ricorsivamente sui figli): ogni height costa e il totale è (ogni nodo è contato una volta per ciascun antenato), cioè più di appena l'albero ha altezza non costante (in un albero bilanciato ). Esempio: in un albero perfetto di altezza ogni livello ha nodi ciascuno con un sottoalbero di dimensione circa , quindi height chiamata su ogni nodo costa circa per livello, in totale (SommatorieIl simbolo di sommatoria, le sue proprietà (linearità, additività, cambio di indice) e le somme notevoli di Gauss e geometrica.Sommatorie →, Esponenziale e logaritmoLa funzione esponenziale a^x (base positiva diversa da 1) e la sua inversa, il logaritmo in base a, con grafici e proprietà.Esponenziale e logaritmo →).
Esempio
Albero : check(D) , check(E) ; in : , restituisce ; check(C) ; in : , restituisce bilanciato. Tabella dell'esempio bilanciato (altezza vuoto ):
| nodo | risultato | |||
|---|---|---|---|---|
| (foglia) | (true, ) | (true, ) | 0 | (true, 0) |
| (foglia) | (true, ) | (true, ) | 0 | (true, 0) |
| : (true, 0) | : (true, 0) | 0 | (true, 1) | |
| (foglia) | (true, ) | (true, ) | 0 | (true, 0) |
| : (true, 1) | : (true, 0) | 1 | (true, 2) |
Albero a catena (solo figli sinistri): in le altezze dei due vuoti sono : ; in : , , differenza : ; in : , , differenza : non bilanciato. (Controllato su 3000 alberi casuali confrontando con la definizione.)
Errori comuni
- Usare l'altezza per l'albero vuoto: confonde il vuoto con una foglia e fa dichiarare bilanciato un nodo con un solo figlio che a sua volta ha un figlio (altezze e , differenza ), mentre le altezze corrette sono e (differenza ).
- Controllare il bilanciamento solo alla radice: la definizione vale per ogni nodo.
- Calcolare
heightad ogni nodo con una funzione separata: . - Non specificare input e output della procedura ausiliaria (richiesto dal testo).
Versione ripasso
Testo. Albero binario bilanciato = per ogni nodo le altezze dei sottoalberi sinistro e destro differiscono al più di . Algoritmo ricorsivo isBalanced con input/output, e complessità in , , .
- Idea: postorder che restituisce (balanced, height) (altezza extra); vuoto , foglia (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 →).
check(v):null⇒ ; e dai figli; se uno èfalse⇒ ; se ⇒ ; altrimenti .- Complessità: una chiamata per nodo e per sottoalbero vuoto, costo costante: ; se è bilanciato ⇒ . Soluzione ingenua con
heightper ogni nodo: . - Codice:
check(null) = (true, -1);(bL,hL) <- check(left); sebL = false⇒(false, 0);(bR,hR) <- check(right); sebR = false⇒(false, 0); se ⇒(false, 0); altrimenti(true, 1 + max(hL,hR)). - Esempio: : : ; : ⇒ bilanciato; catena a sinistra: in differenza ⇒ non bilanciato.
- Errori: vuoto ; controllo solo alla radice;
heightseparata ad ogni nodo; input/output non specificati.