Alberi binari
In questa pagina 5
Definizione (albero binario e albero binario proprio). Un albero binario è un albero ordinato (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 →) in cui ogni nodo interno ha al più 2 figli, ogni nodo non radice è etichettato come figlio sinistro o destro del padre, e il figlio sinistro precede il destro. Se c'è un solo figlio si assume sia il sinistro. Il sottoalbero sinistro (destro) di è quello radicato nel suo figlio sinistro (destro).
Un albero binario è proprio (o pieno, full) se ogni nodo interno ha esattamente 2 figli. Un albero binario è un caso particolare di albero (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 →) e di grafo senza cicli (Grafi - definizioni e proprietàGrafo G=(V,E) diretto e non diretto, grafo semplice e pesato; incidenza, adiacenza, grado; cammini, cicli, sottografi, grafi connessi e componenti connesse; alberi liberi, foreste, spanning tree e spanning forest; proprietà con dimostrazioni (somma dei gradi = 2m, m <= n(n-1)/2, alberi m = n-1, connessi m >= n-1, foreste m <= n-1).Grafi - definizioni e proprietà →); le interfacce sono ADT (Tipi di dato astrattiUn ADT è definito dalle operazioni e dal loro comportamento, non dalla rappresentazione; interfaccia e implementazione; realizzazione in Python con le classi e in C con header e tipo opaco; esempio di un ADT Frazione.Tipi di dato astratti →).
Esempio. Un albero con la radice, un figlio sinistro con due foglie e un figlio destro foglia è binario proprio: ogni nodo interno ha figli e .
interfaccia BinaryTree estende Tree:
left(p) figlio sinistro di p (null se non esiste)
right(p) figlio destro di p (null se non esiste)
sibling(p) fratello di p (null se non esiste)Relazioni in un albero binario proprio non vuoto
Siano i nodi, le foglie (quindi i nodi interni) e l'altezza.
Teorema (relazioni in un albero binario proprio)
# Relazione 1 2 3 4 5
Esempio. Albero perfetto di altezza : , foglie e .
Le 3, 4 e 5 sono corollari della 1 e della 2. Valori per (intervalli possibili per foglie e nodi):
| foglie : da a | nodi : da a | |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 2 | 3 |
| 2 | da 3 a 4 | da 5 a 7 |
| 3 | da 4 a 8 | da 7 a 15 |
| 4 | da 5 a 16 | da 9 a 31 |
Dimostrazione della 1 (induzione sul numero di nodi interni ). Se l'albero è una sola foglia: . Altrimenti la radice è interna con sottoalberi propri (non vuoti, perché l'albero è proprio) di nodi interni, (i nodi interni dei due sottoalberi più la radice stessa). Per ipotesi , , quindi .
Dimostrazione di (induzione sull'altezza). Base : una sola foglia, . Passo: di altezza ha radice con sottoalberi di altezze , e . Per ipotesi (la seconda disuguaglianza perché e è crescente: 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 →), quindi .
Dimostrazione di (induzione sull'altezza). Base : . Passo: uno dei sottoalberi ha altezza e per ipotesi almeno foglie; l'altro ha almeno foglia (ogni albero non vuoto ne ha una); in totale , che è la tesi per un albero di altezza .
Corollari. Dalla 1, , quindi (relazione 3) e , da cui (relazione 4). Da si ottiene e da si ottiene (relazione 5). Passaggi: , e applicando (funzione crescente, 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 →) a entrambi i membri ; analogamente . Il grafico mostra i due limiti: ogni albero binario proprio con nodi ha l'altezza tra le due curve.
Grafico interattivo: Altezza di un albero binario proprio con n nodi: limite inferiore log2(n+1) − 1 (albero perfetto) e limite superiore (n − 1)/2 (albero a pettine); per n = 31 l'altezza è tra 4 e 15
Casi estremi. : albero perfetto (tutti i livelli pieni), , . : ogni nodo interno ha almeno una foglia come figlio ("a pettine"), , . Quindi in un albero binario proprio l'altezza è almeno logaritmica ma può essere lineare nel numero di nodi. (Verifica: le relazioni 1-5 sono state controllate su 2000 alberi casuali.)
Visita inorder
Definizione (visita inorder). Oltre a preorder e postorder (vedi Visite di alberiVisite in preorder e postorder come schemi generali (template) da adattare; complessità Theta(n + somma dei costi di visita) perché la somma dei figli è n-1; esempi (indice di un libro, spazio occupato in un file system); profondità con il preorder, altezza con il postorder; antenato comune più basso.Visite di alberi →), negli alberi binari si ha la visita inorder: prima il figlio sinistro, poi il padre, poi il figlio destro.
Esempio. Sull'albero con radice e foglie e la visita inorder dà .
Algoritmo inorder(T, v)
if T.left(v) != null then inorder(T, T.left(v))
visita v
if T.right(v) != null then inorder(T, T.right(v))Costo come le altre visite. In un albero binario di ricerca la visita inorder tocca le chiavi in ordine crescente (vedi 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 →).
Espressioni aritmetiche e parse tree
Definizione (parse tree di un'espressione). Un'espressione fully parenthesized in notazione infissa è una costante/variabile oppure con fully parenthesized e Op binario. Il parse tree è l'albero binario proprio che ha nelle foglie costanti e variabili, nei nodi interni gli operatori, con sottoalbero sinistro e destro uguali ai parse tree di ed ; le parentesi sono implicite nella struttura. Con operatori unari l'albero non è più proprio. Le espressioni aritmetiche e la precedenza degli operatori sono quelle di Tipi numerici ed espressioniint, float, complex e bool; operatori aritmetici con divisione intera e modulo; precedenza; conversioni di tipo; modulo math e arrotondamenti.Tipi numerici ed espressioni → (Fondamenti di Informatica); la costruzione del parse tree è una fase della compilazione (Paradigmi di programmazione e linguaggiAlgoritmo e programma; paradigmi imperativo, procedurale, a oggetti, funzionale e dichiarativo; compilazione e interpretazione; confronto tra Python e C.Paradigmi di programmazione e linguaggi →, Dal programma C all'eseguibile ARMCatena di traduzione compilatore, assemblatore, linker e loader; file oggetto, tabella dei simboli e rilocazione; collegamento statico e dinamico; organizzazione della memoria di un processo; chiamare funzioni assembly da C e viceversa, con esempio.Dal programma C all'eseguibile ARM →).
Esempio. con vale .
Esempio: ha radice , figlio sinistro con foglie , figlio destro con foglie e il nodo con foglie . I compilatori costruiscono il parse tree e lo usano per controllo dei tipi, ottimizzazioni e generazione del codice.
Valutazione, postorder: ogni operatore ha bisogno dei valori dei figli.
Algoritmo evaluateExpression(T, v)
Input: parse tree T, nodo v Output: valore dell'espressione di T_v
if T.isInternal(v) then
op <- v.getElement()
x <- evaluateExpression(T, T.left(v))
y <- evaluateExpression(T, T.right(v))
return x op y
else return v.getElement()Costo ( costante). Con l'esempio vale . Traccia del postorder (i valori risalgono dalle foglie): ; ; ; . La visita inorder dello stesso albero dà , cioè l'espressione senza parentesi: perde l'informazione sull'ordine delle operazioni, che solo la struttura dell'albero conserva.
Esempio: heightSum
Definizione (heightsum). La heightsum di un albero binario proprio è la somma delle altezze di tutti i suoi nodi. Con la sola somma restituita da ogni sottoalbero non si potrebbe calcolare l'altezza del padre; si restituisce quindi una coppia (somma, altezza):
Algoritmo heightSum(T, v) Input: v in T Output: (somma delle altezze dei nodi di T_v, altezza di v) if T.isExternal(v) then return (0, 0) (sL, hL) <- heightSum(T, T.left(v)) (sR, hR) <- heightSum(T, T.right(v)) h <- max(hL, hR) + 1 return (sL + sR + h, h)
Esempio. In un albero con la radice, un figlio sinistro con due foglie e un figlio destro con una foglia e un nodo con due foglie, le altezze dei nodi interni sono e la heightsum vale .
Costo (postorder). Per l'albero con radice che ha un figlio sinistro con due foglie e un figlio destro con una foglia e un nodo con due foglie, le altezze dei nodi interni sono e la heightsum è . Traccia dell'algoritmo, coppia (somma, altezza) di ogni sottoalbero: ogni foglia dà ; il figlio sinistro della radice, con due foglie, dà e somma , cioè ; il nodo con due foglie nel sottoalbero destro dà ancora ; il figlio destro, con una foglia e quel nodo , dà e somma , cioè ; la radice, con a sinistra e a destra, dà e somma , cioè . Lezione generale: per ottenere una strategia efficiente conviene spesso calcolare un'informazione più ricca di quella richiesta (qui l'altezza oltre alla somma).
Errori comuni
- Applicare le relazioni 1-5 ad alberi non propri: valgono (con altre costanti) solo per alberi propri.
- Confondere (massimo numero di foglie) con (massimo numero di nodi).
- Usare un preorder per valutare un'espressione: i valori dei figli servono prima.
- Calcolare
heightSumchiamandoheightda ogni nodo: diventa quadratico nel caso pessimo.
Versione ripasso
- Albero binario: ogni nodo ha al più figli, ordinati (il figlio unico è il sinistro). Proprio (full): ogni nodo interno ha esattamente figli. Interfaccia
BinaryTree:left(p),right(p),sibling(p)(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 →, Tipi di dato astrattiUn ADT è definito dalle operazioni e dal loro comportamento, non dalla rappresentazione; interfaccia e implementazione; realizzazione in Python con le classi e in C con header e tipo opaco; esempio di un ADT Frazione.Tipi di dato astratti →). - Relazioni (proprio, non vuoto, nodi, foglie, altezza ):
| # | Relazione |
|---|---|
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 |
- Prove:
- (1) induzione sui nodi interni : ;
- per induzione sull'altezza: ;
- : un sottoalbero ha altezza (almeno foglie), l'altro almeno foglia;
- (3), (4), (5) da e , applicando a .
- Esempio: perfetto di altezza : , , .
- Casi estremi: albero perfetto (); albero a pettine (). Altezza almeno logaritmica, al più lineare.
- Inorder: sinistro, padre, destro; costo ; in un albero di ricerca dà le chiavi crescenti (vedi 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 →).
- Parse tree: foglie = costanti e variabili, nodi interni = operatori. Esempio con vale . L'inorder dà : perde l'ordine delle operazioni.
- evaluateExpression: postorder; nodo interno:
x <- eval(left),y <- eval(right),return x op y; foglia: il suo valore. Costo (vedi Visite di alberiVisite in preorder e postorder come schemi generali (template) da adattare; complessità Theta(n + somma dei costi di visita) perché la somma dei figli è n-1; esempi (indice di un libro, spazio occupato in un file system); profondità con il preorder, altezza con il postorder; antenato comune più basso.Visite di alberi →). - heightSum: postorder che restituisce la coppia (somma, altezza); foglia ;
h <- max(hL,hR)+1;return (sL+sR+h, h). Costo . Esempio: altezze interne , heightsum . Conviene calcolare un'informazione più ricca di quella richiesta. - Altezza: . L'albero perfetto ha , quello a pettine .
- Visita inorder: su un albero con radice e foglie e dà ; costo .
- Verifica: le relazioni 1-5 sono state controllate su alberi casuali; come per ogni relazione, valgono solo per alberi propri.
- Errori tipici: applicare le relazioni ad alberi non propri; confondere foglie con nodi; usare il preorder per valutare un'espressione; chiamare
heightda ogni nodo inheightSum(diventa quadratico).
Esercizi su questo argomento
- Esercizio 7 · dimostrazioni sulle foglie di un albero binario proprio
- Esercizio 9 · foglia più profonda di un albero binario proprio
- Esercizio 12 · inserimenti e rimozioni in uno heap
- Esercizio 16 · alberi binari di ricerca, inserimenti e visita inorder
- Esercizio 27 · C, resistenza equivalente di un circuito (albero)