Dati e Algoritmi 1: A. Pietracaprina
Alberi Binari
1
Alberi Binari
Definizione
Un alberto binario T è un albero ordinato tale che
• ogni nodo interno ha ≤ 2 figli
• ogni nodo non radice è etichettato come figlio sinistro (sx) o
destro (dx) di suo padre
• figlio sx viene prima di figlio dx nell’ordinamento
Nota
A meno di casi particolari assumiamo che se c’è un solo figlio,
questo sia il figlio sx.
2
Alberio Binario: Esempio e Terminologia
v"
so#oalbero)sx!di!v"
so#oalbero)dx!di!v"
3
Alberi Binari Propri
Definizione
Albero Binario Proprio T : albero binario tale che:
• ogni nodo interno ha esattamente 2 figli
Albero'Binario'
Albero'Binario'Proprio'
Osservazione
In letteratura gli alberi propri sono anche chiamati pieni
In inglese (e.g., sul libro):
• proprio = proper
• pieno = full
4
Dal libro:
Inoltre noi includiamo nell’interfaccia la dichiarazione dei metodi:
• boolean hasLeft(Position<E> v);
• boolean hasRight(Position<E> v);
5
Proprietà di un albero binario proprio T non vuoto
n = numero di nodi in T
m = numero di foglie in T
n − m = numero di nodi interni in T
h = altezza di T
Proprietà:
1
m =n−m+1
2
h + 1 ≤ m ≤ 2h
3
h ≤ n − m ≤ 2h − 1
4
2h + 1 ≤ n ≤ 2h+1 − 1
5
log2 (n + 1) − 1 ≤ h ≤
n−1
2
6
Osservazioni
• Proprietà 3),4) e 5) sono corollari di 1) e 2)
• in [GTG14]:
• nE = m, nI = n − m
• Proprietà 1): Proposition 8.8 ⇒ Esercizio R-8.8
• Proprietà 2),3),4) e 5): Proposition 8.7 ⇒ Esercizio R-8.7
(Nel testo la proposizione enuncia proprietà analoghe anche
per alberi non propri.)
7
Dimostrazione di 1)
m =n−m+1
Dimostrazione
Per induzione su h ≥ 0
• k = 0, h0 = 0
• base: h = 0 ⇒ m = 1 e n = 1 ⇒ OK
• passo induttivo: fissiamo h ≥ 0
Hp. induttiva: proprietà vale ∀ albero di altezza h0 ≤ h
Consideriamo T di altezza h + 1 ≥ 1
r"
h1"
T1"
h2"
h+1"
T2"
h+1="max${"h1","h2"}"+"1""(h="max${"h1","h2"}")"
8
Proprietà: m = n − m + 1
Dimostrazione (continua)
r"
h1"
T1"
h2"
h+1"
T2"
h+1="max${"h1","h2"}"+"1""(h="max${"h1","h2"}")"
mi = num. foglie in Ti , i = 1, 2
ni = num. nodi in Ti , i = 1, 2
⇒ m = m1 + m2 e n = n1 + n2 + 1
m = m1 + m2 =(hp.ind.) n1 − m1 + 1 + n2 − m2 + 1 = n − m + 1
9
Dimostrazione in [GTG14]
Proprietà: m = n − m + 1
Dimostrazione
Due casi:
• n = 1: banale
• n > 1 sino a quando l’albero ha ≥ 2 nodi eseguo la seguente
operazione:
Ottengo ancora un albero binario proprio con n − 2 nodi
Quando arrivo ad un albero binario con 1 solo nodo (foglia) mi
fermo. Avrò eliminato m − 1 foglie e m − 1 nodi interni, e mi è
rimasta una foglia ⇒ n = 2m − 2 + 1 ⇒ m = n − m + 1
10
Dimostrazione di 2)
h + 1 ≤ m ≤ 2h , cioè: m ≤ 2h e m ≥ h + 1
Dimostriamo m ≤ 2h
Dimostrazione
Per induzione su h ≥ 0
• base: h = 0 ⇒ m = 1: OK
• passo induttivo: fissiamo h ≥ 0
Hp. induttiva: proprietà vale ∀ albero di altezza h0 ≤ h
Consideriamo T di altezza h + 1 ≥ 1
r"
h1"
T1"
h2"
h+1"
T2"
h+1="max${"h1","h2"}"+"1""(h="max${"h1","h2"}")"
11
Consideriamo m ≤ 2h
Dimostrazione (continua)
r"
h1"
T1"
h2"
h+1"
T2"
h+1="max${"h1","h2"}"+"1""(h="max${"h1","h2"}")"
mi = num. foglie in Ti , i = 1, 2 ⇒ m = m1 + m2
m = m1 + m2 ≤(hp.ind.) 2h1 + 2h2 ≤ 2 × 2h = 2h+1
m ≥ h + 1: ESERCIZIO PER CASA
Nota
Un albero binario proprio ha altezza h = Ω (log m). E se non è
proprio? ESERCIZIO
12
Alberi Binari Propri Estremi
h"
"m"="h"+1""
"n"–"m"="h"
"n"="2h"+1""
"h"="(n+1)/2"
!m!=!2h!
!n!=!2h+1!(!1!!
!n!–!m!=!2h(1! !h!=!log2(n+1)!(!1!
2h!
13
Alberi Binari e Espressioni Aritmetiche
Definizione
Una espressione fully parenthesized (notazione infissa) è:
• una costante o variabile a, oppure
• (E1 Op E2 ), dove E1 , E2 sono espressioni fully parenthesized e
Op è un operatore binario
Esempio
((15 + x) ∗ (7 − (9 ÷ 3)))
14
Albero binario associato ad una espressione
(Parse Tree)
Definizione
.
• nodi foglia = costanti o variabili
.
• nodi interni = operatori
• ogni sottoalbero rappresenta una espressione, e la radice è
associata al valore dell’espressione
Esempio
*"
&"
+"
15"
N.B.: è un albero binario
proprio
x"
7"
÷"
9"
3"
15
Se si ammettono operatori unari, l’albero non è più proprio
Esempio: −15 ∗ (3 + 7)
*"
+"
!"
15"
3"
7"
Osservazione
Nei compilatori
Espressione)
(notazione)
infissa)))
ParseTree)
Sequenza)di)operazioni)
facilmente)calcolabile)a)
run;me)(e.g.,)notazione)
pos?issa))
Type)checking,)verifiche,)
oDmizzazioni)
16
Valutazione dell’espressione
Algoritmo evaluateExpression(T ,v )
Input: Parse Tree T for E , v ∈ T
Output: valore associato al sottoalbero Tv
if T .isInternal(v ) then
op ← v .element();
x ← evaluateExpression(T ,T .left(v ));
y ← evaluateExpression(T ,T .right(v ));
return x op y ;
else
return v .element();
Osservazioni
• Visita in postorder
• Chiamata iniziale: evaluateExpression(T , T .root()).
• Complessità = O (n), dove n è il numero di nodi in T
17
Definizione
Una espressione in notazione postfissa è:
• una costante o variabile a, oppure
• E1 E2 Op, dove E1 , E2 sono espressioni in notazione postfissa
e Op è un operatore binario
Esempio
Espressione f.p. in notazione infissa:
((15 + x) ∗ (7 − (9 ÷ 3)))
*"
&"
+"
15"
x"
7"
÷"
9"
3"
Espressione in notazione postfissa (ottenibile dalla visita postorder del parse
tree): 15 x + 7 9 3 ÷ − ∗
Osservazione
I compilatori spesso rappresentano le espressioni nel codice eseguibile con
notazione postfissa (esempio: Java bycode usa la notazione postfissa).
18
Visita inorder
Idea: prima il figlio sx, poi il padre, poi il figlio dx
Algoritmo inorder(T ,v )
Input: T , v ∈ T
Output: visita inorder di Tv
if T .hasLeft(v ) then inorder(T ,T .left(v );
visita v ;
if T .hasRight(v ) then inorder(T ,T .right(v );
Osservazioni:
• Chiamata iniziale: inorder(T , T .root()).
• Complessità = O (n), dove n è il numero di nodi in T . Stessa
analisi delle visite in preorder/postorder.
• La visita inorder è usata, ad esempio, negli alberi binari di
ricerca, per stampare i contenuti dei nodi in ordine crescente
di chiave.
19
Riferimenti dal testo
[GTG14]:
• Par. 8.2
• Par. 8.4.3-8.4.5
20
Caso di studio 3: Decision tree
• Machine Learning: Area dell’informatica che si occupa dello
sviluppo di algoritmi e modelli per analizzare dati allo scopo di
scoprire nuova informazione e fare previsioni, a supporto di
processi decisionali.
• Supervised learning: si impara da dati storici per fare
previsioni future. I dati da trattare sono record caratterizzati
da un insieme di feature (o attributi) e una classe. Il problema
della classification consiste nell’analizzare un tranining set di
record classificati per trovare un modello che predica una
classe a partire dalle feature. Il modello è poi applicato
successivamente per assegnare una classe a nuovi record non
classificati.
• I Decision tree sono tra i modelli più utilizzati e importanti
nell’ambito del machine learning. Forniscono buona
accuratezza, sono semplici da derivare, e sono descrittivi.
Inoltre possono essere utilizzati in ensemble.
21
Caso di studio 3: Decision tree (continua)
22
Esercizi
Esercizio 1
Sia T il parse tree associato a una espressione aritmetica E fully
parenthesized in notazione infissa che usa solo operatori binari.
Sviluppare un algoritmo ricorsivo infix che ricavi l’espressione E a
partire dal parse tree T , e analizzarne la complessità in tempo.
Esempio
L’espressione associata è:
*"
15"
((15 + x) ∗ (7 − (9 ÷ 3)))
&"
+"
x"
7"
÷"
9"
3"
La visita inorder produrrebbe
la sequenza: 15 + x ∗ 7 − 9 ÷ 3.
Basta quindi aggiungere le
opportune parentesi.
23
L’algoritmo è il seguente (si usa + per indicare la concatenazione
di stringhe):
Algoritmo infix(T,v)
input Parse tree T , nodo v ∈ T
output espressione Ev rappresentata da Tv
if (T.isExternal(v)) then return v.element()
else return ’(’+infix(T,T.left(v))+v.element()+infix(T,T.right(v))+’)’
• Per generare l’espressione completa associata a T , basterà
invocare l’algoritmo con v=T.root().
• Complessità è lineare nel numero di nodi del (sotto)albero sul
quale è invocato. (Come una qualsiasi visita.)
24
Esercizio 2
Sia T un albero binario proprio. Si definisca la heightsum di T
come la somma delle altezze di tutti i suoi nodi. (Si ricordi che
l’altezza di una foglia è 0, e quella di un nodo interno è 1+la
massima altezza dei suoi figli.)
1
Per calcolare la heightsum dell’albero, si sviluppi un algoritmo
ricorsivo heightSum(T , v ) che calcola la heightsum del
sottoalbero Tv , per un nodo arbitrario v .
2
Analizzare la complessità di heightSum(T,T.root()).
L’idea è quella di adattare la visita in postorder facendo restituire a
heightSum(T , v ) non solo la somma delle altezze dei nodi di Tv , ma
anche l’altezza di v . Altrimenti, dopo aver calcolato ricorsivamente le
heightsum dei sottoalberi figli non si potrebbe calcolare l’altezza di v e
quindi la heightsum di Tv . Questo è un esempio in cui calcolando
un’informazione più ricca (somma delle altezze e altezza) si ottiene una
strategia algoritmica più efficiente.
25
1
L’algoritmo è il seguente:
Algoritmo heightSum(T , v )
input v ∈ T
output somma altezze nodi di Tv , 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
s ← sL + sR + h
return (s, h)
2
• Prima invocazione: heightSum(T ,T .root())
• Complessità: O (n), come visita in postorder.
26
Esercizio 3 (C-8.41 in [GTG14])
Si consideri un albero binario proprio T . Progettare un metodo
preorderNext(v) che restituisce il nodo visitato dopo v nella
visita in preorder di T , o null, se v è l’ultimo nodo visitato.
Osservazioni
• Se v è un nodo interno, allora il suo successore nella visita in
preorder è il suo figlio sinisitro.
• Se v è una foglia, dobbiamo risalire sino a trovare il primo
antenato u (cioè l’antenato più profondo) tale che v sta nel
sottoalbero sinistro di u. In questo caso, il successore di v
nella visita in preorder è il figlio destro di u. Se tale antenato
u non esiste, significa che v è l’ultimo nodo visitato dalla vista
in preorder di T
27
L’algoritmo è il seguente:
Algoritmo preorderNext(v )
input v ∈ T
output successore di v in preorder (o null se non esiste)
if (T .isInternal(v )) then return T .left(v )
while (!T.isRoot(v )) do {
if (v =T .left(T .parent(v ))) then
return T .right(T .parent(v ))
else v ← T .parent(v )
}
return null
Analisi
• Numero di iterazioni del while ≤ profondità di v .
• In ciascuna iterazione Θ (1) operazioni.
• Per il resto l’algoritmo esegue Θ (1) operazioni.
• Dato che la profondità di v è al più l’altezza h di T , concludiamo
che la complessità è O (h).
28
Esercizio 4
Dimostrare che in un albero binario proprio T con m foglie e
altezza h vale che m ≥ h + 1. Cercare due prove diverse: una con
l’induzione e una senza.
Prova per induzione sull’altezza h dell’albero.
• BASE: la proprietà è vera per un albero di altezza h = 0, che
quindi ha un solo nodo (foglia) e m = 1.
• PASSO INDUTTIVO: Supponiamo che la proprietà sia vera
per alberi di altezza al più h, con h ≥ 0 fissato, e consideriamo
un albero T di altezza h + 1 ≥ 1. Chiaramente la radice di T
deve essere un nodo interno e uno dei due suoi sottoalberi
deve avere altezza h. Il sottoalbero di altezza h deve avere
almeno h + 1 foglie (hp. induttiva), mentre l’altro deve avere
almeno una foglia, per un totale di almeno h + 2 foglie.
29
Prova senza induzione. Un albero di altezza h deve avere una
foglia v di profondità h. Sia r = v0 → v1 → · · · → vh = v il
percorso dalla radice a tale foglia. Gli h sottoalberi radicati nei
fratelli di vi , per 1 ≤ i ≤ h, sono disgiunti e devono avere almeno
una foglia ciascuno. Insieme a v questo somma a un totale di
almeno h + 1 foglie.
30
Riepilogo sugli alberi (binari e non)
• Definizioni: albero, albero binario (proprio), antenati,
discendenti, sottoalbero, profondità di un nodo, altezza di un
nodo e di un albero.
• Relazione tra altezza di un albero e profondità delle foglie
• Algoritmi per il calcolo della profondità/altezza di un nodo e
dell’altezza di un albero
• Relazioni tra numero di nodi interni, foglie e altezza in un
albero binario proprio
• Visite: preorder, postorder, inorder e loro applicazioni
• Algoritmi di vista come template generali
31
Esempio domande prima parte
• Come sono definiti gli antenati di un nodo in un albero T ?
• Specificare la relazione di ricorrenza che definisce la
complessità dell’algoritmo ricorsivo per il calcolo della
profondità di un nodo.
• Descrivere l’algoritmo per il calcolo dell’altezza di un albero T
indicandone, senza dimostrarla, la complessità.
• Dimostrare che l’altezza di un albero è uguale alla massima
profondità di una sua foglia
• Sia T un albero binario proprio con n − m nodi interni e m
foglie (n nodi totali). Dimostrare che m = n − m + 1.
32