Algoritmi e Strutture Dati Alberi binari di ricerca

!
!
Dizionari
Algoritmi e Strutture Dati
✦
Dizionario
✦
Insieme dinamico che implementa le seguenti funzionalità
!
ITEM lookup(ITEM k)
Alberi binari di ricerca
insert(ITEM k, ITEM v)
!
!
!
Alberto Montresor
remove(ITEM k)
✦
Esempi di implementazione
✦
Università di Trento
!
!
!
Array ordinato
✦
✦
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. To view a
copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative
Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.
1
© Alberto Montresor
Alberi binari di ricerca (ABR)
✦
✦
✦
Portare l'idea di ricerca binaria in un albero
✦
✦
Ogni nodo u contiene una chiave u.key associata ad un valore u.value
✦
Le chiavi appartengono ad un insieme totalmente ordinato
✦
15
6
4
8
12
18
3
Come devo visitare l'albero per ottenere la lista ordinata dei valori?
Dettagli implementativi
✦
1. Le chiavi dei nodi del sottoalbero sinistro di u sono minori di u.key
Le proprietà 1. e 2. permettono di realizzare un algoritmo di ricerca dicotomica
Domanda – Proprietà di ordine
✦
Proprietà
© Alberto Montresor
2
Proprietà di ricerca
✦
Definizione
2. Le chiavi dei nodi del sottoalbero destro di u sono maggiori di u.key
Ricerca/cancellazione O(n), inserimento O(1)
© Alberto Montresor
✦
10
✦
Lista non ordinata
Alberi binari di ricerca (ABR)
Idea “ispiratrice”
✦
Ricerca O(log n), inserimento/cancellazione O(n)
Ogni nodo deve mantenere
✦
Figlio sinistro, destro
✦
Padre
✦
Chiave
✦
Valore
© Alberto Montresor
Padre
Key, Value
Figlio
sinistro
Figlio
destro
4
Alberi binari di ricerca: Specifica
✦
Ricerca: esempio
!
Operazioni ammesse su ABR
TREE key()
TREE successorNode(ITEM T)
TREE value()
TREE predecessorNode(ITEM T)
TREE left()
TREE min()
TREE right()
TREE max()
Ricerca del valore 4
4 < 6
T
4 sta nel sottoalbero 6
sinistro di 6
2
8
TREE parent()
!
1
4
TREE lookup(ITEM k)
TREE insert(ITEM k, ITEM d)
3
TREE delete()
!
!
5
© Alberto Montresor
Ricerca: esempio
Ricerca: esempio
Ricerca del valore 4
2
1
Ricerca del valore 4
4 > 2
T
4 = 4
T
4 sta nel sottoalbero 6
trovato!
6
destro di 2
8
2
4
1
3
© Alberto Montresor
6
© Alberto Montresor
8
4
3
7
© Alberto Montresor
8
else
% Caso (2) - Solo figlio dx / Caso (1)
t
u.right
Ricerca: Implementazione
Ricerca del minimo e del massimo: Esempi
link(u.parent,
t, x)
di ricerca,
e possono
essere utilizzate per realizzare le relative operazioni degli insiemi e dei
if u.parent = nil then T = t
dizionari.
Per illustrare
un approccio
complementare rispetto a quello utilizzato introducendo
Sottoalbero con
T REE lookupNode
(T REE
T, I TEM x)
delete u
radice 2:
gli return
alberi
proponiamo
versione iterativa delle procedure suddette.
Tnil and
if T 6=binari,
T.key 6= xuna
then
La procedura
lookupNode
() cerca
il nodo
contenente
- minimo 1
return lookupNode
(iif(x
< T.key,
T.left,
T.right),la
x)chiave x nell’albero binario di
Ricorsiva
ricerca
radicato
in
T
;
restituisce
nil,
nel
caso
che
la
chiave
non
sia
presente,
il
puntatore
al
else
6
- massimo 4
nodo contenente
return T x, altrimenti. La complessità della procedura è O(h), dove h è l’altezza
– il caso (2) con solo un figlio sinistro è semplice; il figlio sinistro viene collegato al padre di
dell’albero.
u; se il padre è assente, u era radice e il suo figlio sinistro diventa la nuova radice.
–TilREE
casolookupNode
(2) con solo(T
unREE
figlio
il figlio destro viene collegato al padre di
T,destro
I TEMè simmetrico;
x)
u; se il padre è assente, u era radice e il suo figlio destro diventa la nuova radice. Si noti
while T ⇥= nil and T.key ⇥= x do
che in pratica questo codice gestisce anche il caso (1), dove però il figlio Iterativa
destro di u è nil.
T
iif(x < T.key, T.left, T.right)
Se sia u che il suo figlio destro sono nil, l’albero è ora vuoto e la nuova radice diventa per
return Tnil.
l’appunto
Sottoalbero con
radice 8:
T
- minimo 8
- massimo 15
2
1
8
4
12
3
La memoria
associata
al nodo uchiavi-elemento,
viene rimossa e la radice
(potenzialmente
modificata)
viePer inserire
associazioni
procedura
insertNode()
effettua innanzitutto
ne
Richiedendo
massimo
una discesa (),
radice-foglia,
ancheilquesta
unarestituita
ricerca,alinchiamante.
modo simile
a quanto alvisto
per lookupNode
per localizzare
nodo u conprocedura
ha
costo
O(h).
tenente l’elemento (in caso di modifica dell’associazione corrente) o il nodo p che diventerà
A differenza
dellenodo
tabelle
hash che verranno
presentate
capitolo,
gli alberi
il padre
del nuovo
contenente
l’elemento
(in casonel
di prossimo
inserzione).
Nel caso
il nodo sia
diAlberto
ricerca
mantengono l’ordinamento fra i valori. Un operatore min() che restituisca il nodoe questo
©trovato,
Montresorviene aggiornato solo il campo value; altrimenti viene creato un nuovo nodo, 9
© Alberto Montresor
contenente
il
minimo
può
essere
realizzato
facilmente
in
tempo
O(h).
Basta
infatti
effettuare
viene agganciato come figlio sinistro o destro di p, a seconda del valore della chiave, dalla
una
ricercadel
in cui si segue
sempre
il figlio
sinistro, fino a trovare un nodo che non ha figlio
Ricerca
massimo:
Pseudo-codice
Ricerca del successore/predecessore
procedura
di minimo
appoggioe del
link().
insertNode
() restituisce un puntatore all’albero, che corrisponde
sinistro. L’operatore max() è simmetrico, basta seguire sempre il figlio destro.
all’albero esistente, se questo conteneva già almeno un nodo, o corrisponde al nodo creato, se
✦
questo
è il primo a popolare l’albero (ovvero seTpREE
= nil).
Come prima la complessità è O(h), Definizione
T REE min(T REE T )
max(T REE T )
✦ Il successore di un nodo u è il ma si noti che l’altezza può crescere di uno.
while T.left ⇥= nil do
while T.right ⇥= nil do
più piccolo nodo maggiore di u
T
T.left
T
T.right
link
(T REE
return
T p, T REE u, I TEM x)
return T
✦ Due casi
if u ⇥= nil then u.parent
p
✦ u ha un figlio destro
if p ⇥= nil then
if x < p.key then p.left
u
✦ Il successore u' è il minimo
11
else p.right
u
del sottoalbero destro di u
✦
La procedura link(), utilizzata anche dalla procedura removeNode(), gestisce le due azioni
necessarie per collegare un nodo padre p ad un nodo figlio u: modificare il puntatore al padre di
u, e inserire u come figlio sinistro o destro di p, a seconda del valore del parametro x che viene
Esempio: successore di 2 è 3
9
15
10
T
6
u
2
1
8
12
4
3
9
15
u'
© Alberto Montresor
11
© Alberto Montresor
12
Il codice di successorNode() segue semplicemente i due casi; il codice di predecessorNode
()
è simmetrico.
Ricerca
del successore: Pseudo-codice (iterativo)
Ricerca del successore/predecessore
✦
Definizione
✦
✦
Il successore di un nodo u è il più piccolo nodo maggiore di u
u'
if t = nil then
return t
if t.right ⇥= nil then
return min(t.right())
T REE p
t.parent
while p ⇥= nil and t = p.right do
t
p
p
p.parent
return p
6
Due casi
✦
✦
✦
2
u non ha un figlio destro
Il successore è il primo avo u' tale per cui u sta nel sottoalbero sinistro di u'
Esempio: successore di 4 è 6
1
8
12
3
4
T REE predecessorNode(T REE t)
T REE successorNode(T REE t)
T
9
if t = nil then
return t
if t.left ⇥= nil then
return max(t.left())
T REE p
t.parent
while p ⇥= nil and t = p.left do
t
p
p
p.parent
return p
15
u
13
© Alberto Montresor
Ricerca: costo computazionale
✦
✦
✦
Le operazioni di ricerca sono
confinate ai nodi posizionati lungo un singolo percorso (path) dalla radice ad una foglia
5 < 6
Inserimento valore 5
5 > 2
T
h = altezza dell’albero
5 > 4
6
Tempo di ricerca: O(h)
2
8
Domanda
✦
✦
Inserimento
In generale
✦
14
© Alberto Montresor
Qual è il caso pessimo?
✦
44
1
Domanda
12
Qual è il caso ottimo?
3
© Alberto Montresor
15
© Alberto Montresor
5
9
15
16
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
101
Inserimento: pseudo-codice (iterativo)
questo è il primo a popolare l’albero (ovvero se p = nil). Come prima la complessità è O(h),
Inserimento: pseudo-codice (iterativo)
ma si noti che l’altezza può crescere di uno.
T REE insertNode(T REE T, I TEM x, I TEM v)
T REE p
nil
T REE u
T
while u ⇥= nil and u.key ⇥= x do
p
u
u
iif(x < u.key, u.left, u.right)
if u ⇥= nil and u.key = x then
u.value
v
else
T REE n
Tree(x, v)
link(p, n, x)
if p = nil then return n
% Primo nodo ad essere inserito
return T
% Ritorna albero non modificato
Caso 1: Il nodo u da eliminare non ha figli
if u ⇥= nil then u.parent
p
if p ⇥= nil then
if x < p.key then p.left
u
else p.right
u
% Cerca posizione inserimento
% Chiave già presente
confrontato con il contenuto del padre. Come casi particolari, p può essere nil, che significa
che u è la nuova radice; oppure u può essere nil, che significa che un nodo è stato cancellato e
17
© Alberto Montresor
nil sostituisce il figlio corrispondente nel padre. link() ha costo O(1).
Per realizzare removeNode() si procede in modo analogo all’inserzione, con una compliCancellazione
cazione
in più data dal fatto che l’elemento x da cancellare si trova in un nodo u che non
necessariamente è una foglia. Possono sorgere tre casi, illustrati nella Fig. 6.2.
✦
link(T REE p, T REE u, I TEM x)
% Padre
T
(1) Se
non ha figli, allora
u è una foglia che viene semplicemente rimossa. C’è da gestire
✦ u
Semplicemente
si elimina
6
tuttavia il caso particolare in cui u sia l’unico nodo dell’albero.
(2)
Se u ha un solo figlio f , allora u è rimosso rendendo f figlio del padre di u.
✦ Esempio:
(3) Se
u ha due figli, ci si può ridurre al caso (1) o (2) sostituendo l’elemento da cancellare
✦ Eliminazione nodo 5
2
8
x con il più piccolo elemento y tale che y > x, che si trova nel nodo s raggiungibile
scendendo sempre a sinistra nel sottoalbero radicato nel figlio destro di u. L’elemento y
prende il posto di x nel nodo u mentre viene rimosso il nodo s che, per definizione, non
può avere un figlio sinistro.
1
44
12
La procedura link(), utilizzata anche dalla procedura removeNode(), gestisce le due azioni
necessarie per collegare un nodo padre p ad un nodo figlio u: modificare il puntatore al padre di
u, e inserire u come figlio sinistro o destro di p, a seconda del valore del parametro x che viene
Cancellazione
✦
Caso 2: Il nodo u da eliminare ha un unico figlio f
✦
✦
✦
T
Si elimina u
Si attacca f all'ex-padre p di u
in sostituzione di u (short-cut)
6
2
p
8
Esempio:
✦
Cancellazione di 4
1
4
12
u
La procedura removeNode() restituisce il puntatore alla radice dell’albero, che può cambiare se il nodo cancellato è proprio la radice. La procedura inizia cercando tramite lookupNode()
9
il nodo da cancellare u; la radice viene mantenuta3nel puntatore T . 5Se u non è stato trovato, la15
procedura termina restituendo la radice inalterata.
u
A questo punto, la procedura è organizzata nel modo seguente:
– il caso (3) appare per primo, in quanto si riduce al caso (1) o (2); innanzitutto viene identificato il nodo s e la sua associazione chiave-valore viene ricopiata nel nodo u; a questo
© Alberto Montresor
punto, il puntatore u assume il valore di s e si passa a gestire la cancellazione di s tramite 19
18
© Alberto Montresor
3
© Alberto Montresor
f
9
15
20
102
Cancellazione
✦
Cancellazione: Pseudo-codice
Caso 3: Il nodo u da eliminare ha due figli
✦
✦
✦
T
Si individua il successore s del nodo u
Il successore non ha figlio sinistro
7
Si “stacca” il successore
23
Si attacca l'eventuale
figlio destro di s al
padre di s (short-cut)
✦
Si copia s su u
✦
Si rimuove il nodo s
u
8
5
1
s
12
6
3
9
15
4
21
© Alberto Montresor
Cancellazione – Dimostrazione di correttezza
✦
✦
✦
✦
Eliminare foglie non cambia la proprietà di ordine dei nodi rimanenti
Caso 2 - solo un figlio (destro o sinistro)
✦
Se u è il figlio destro (sinistro) di p, tutti i i valori nel sottoalbero di f sono maggiori (minori) di p
Quindi f può essere attaccato come figlio destro (sinistro) di p al posto di u
Caso 3 - due figli
✦
✦
Il successore s
✦
è sicuramente maggiore di tutti i nodi del sottoalbero sinistro di u
✦
è sicuramente minore di tutti i nodi del sottoalbero destro di u
Quindi può essere sostituito a u
© Alberto Montresor
T REE removeNode(T REE T, I TEM x)
T REE u
lookupNode(T, x)
if u ⇥= nil then
if u.left ⇥= nil and u.right ⇥= nil then
T REE s
u.right
while s.left ⇥= nil do s
s.left
u.key
s.key
u.value
s.value
u
s
T REE t
if u.left ⇥= nil and u.right = nil then
t
u.left
else
t
u.right
link(u.parent, t, x)
if u.parent = nil then T = t
delete u
return T
% Caso 3
% Caso (2) - Solo figlio sx
% Caso (2) - Solo figlio dx / Caso (1)
22
© Alberto Montresor
Modifica: costo computazionale
– il caso (2) con solo un figlio sinistro è semplice; il figlio sinistro viene collegato al padre di
u;generale
se il padre è assente, u era radice e il suo figlio sinistro diventa la nuova radice.
✦ In
– il✦ caso (2) con solo un figlio destro è simmetrico; il figlio destro viene collegato al padre di
Le operazioni di modifica sono
u; se il padre è assente, u era radice e il suo figlio destro diventa la nuova radice. Si noti
confinate ai nodi posizionati che in pratica questo codice gestisce anche il caso (1), dove però il figlio destro di u è nil.
lungo un singolo percorso altezza
dell’albero
Se sia u che il suo figlio destro sono nil, l’albero è ora vuotohe=la
nuova radice
diventa per
(path) dalla radice ad una foglia
l’appunto nil.
✦ Tempo di ricerca: O(h)
La memoria associata al nodo u viene rimossa e la radice (potenzialmente modificata) viene restituita al chiamante. Richiedendo al massimo una discesa radice-foglia, anche questa
procedura ha costo O(h).
A differenza delle tabelle hash che verranno presentate nel prossimo capitolo, gli alberi
di ricerca mantengono l’ordinamento fra i valori. Un operatore min() che restituisca il nodo
contenente il minimo può essere realizzato facilmente in tempo O(h). Basta infatti effettuare
una ricerca in cui si segue sempre il figlio sinistro, fino a trovare un nodo che non ha figlio
sinistro. L’operatore max() è simmetrico, basta seguire sempre il figlio destro.
Caso 1 - nessun figlio
✦
Algoritmi e Strutture di Dati
23
T REE min(T REE T )
while T.left ⇥= nil do
© Alberto Montresor
T REE max(T REE T )
while T.right ⇥= nil do
24
Complessità media
✦
Qual è l'altezza media di un albero di ricerca?
✦
✦
✦
E' possibile dimostrare che l'altezza media è O(log n)
Fattore di bilanciamento
✦
Il fattore di bilanciamento β(v) di un nodo v è la massima differenza di altezza fra
i sottoalberi di v
✦
Alberi AVL (Adel'son-Vel'skii e Landis, 1962)
✦
β(v) ≤ 1 per ogni nodo v
✦
Bilanciamento ottenuto tramite rotazioni
B-Alberi (Bayer, McCreight, 1972)
✦
β(v) = 0 per ogni nodo v
✦
Specializzati per strutture in memoria secondaria
Alberi 2-3 (Hopcroft, 1983)
✦
β(v) = 0 per ogni nodo v
✦
Bilanciamento ottenuto tramite merge/split, grado variabile
Esempio: albero perfetto:
✦
✦
Difficile da trattare
Caso “semplice”: inserimenti in ordine casuale
✦
✦
✦
Caso generale (inserimenti + cancellazione)
✦
✦
Algoritmi di bilanciamento
β(v)=0 per ogni nodo v
In generale:
✦
Sono necessarie tecniche per mantenere bilanciato l'albero
25
© Alberto Montresor
Esempio di rotazione
✦
B-alberi binari (Andersson, 1993)
✦
Alberi Red-Black (Bayer, 1972)
© Alberto Montresor
Alberi Rosso-Nero (Red-Black Treee, RB-Tree)
✦
v
u
u
v
✦
T3
T2
✦
Ogni nodo è colorato di rosso o di nero
✦
Le chiavi vengono mantenute solo nei nodi interni dell’albero
✦
Le foglie sono costituite da nodi nil
Un albero Red-Black deve soddisfare i seguenti vincoli:
2. Tutte le foglie sono nere
T3
3. Entrambi i figli di un nodo rosso sono neri
4. Tutti i cammini semplici da ogni nodo u ad una delle foglie contenute nel
sottoalbero radicato in u hanno lo stesso numero di nodi neri
T1
© Alberto Montresor
Un albero Red-Black è un albero binario di ricerca in cui:
1. La radice è nera
T1
T2
26
27
© Alberto Montresor
28
Alberi Red-Black
✦
✦
Alberi Red-Black
Ogni nodo mantiene
✦
✦
parent
puntatore al padre
✦
left, right
puntatori ai figli sinistro/destro
✦
color
colore
✦
key, data
chiave e dati
✦
✦
✦
Il numero di nodi neri lungo ogni percorso da un nodo v (escluso) ad ogni foglia
(inclusa) del suo sottoalbero è detto altezza nera di v, indicato b(v)
Ben definito perché tutti i percorsi hanno lo stesso numero di nodi neri (regola 4)
Definizione:
✦
Nodo Nil
✦
Definizione:
L’altezza nera di un albero Red-Black è pari all’altezza nera della sua radice
nodo sentinella il cui scopo è evitare di trattare diversamente i puntatori ai nodi dai puntatori nil
✦
al posto di un puntatore nil, si usa un puntatore ad un nodo Nil
✦
ne esiste solo uno, per risparmiare memoria
✦
nodo con figli Nil → foglia nell'ABR corrispondente
29
© Alberto Montresor
Alberi Red-Black: esempio I
30
© Alberto Montresor
Alberi Red-Black: esempio I
3. Entrambi i figli di un nodo rosso sono neri.
Ma un nodo nero può avere figli neri!
4. Ogni percorso da un nodo interno ad un nodo Nil ha lo stesso numero di nodi neri.
Altezza nera di questo albero: 3
30
30
15
70
Nil
5
Nil
60
20
10
Nil
Nil
Nil
50
40
Nil
© Alberto Montresor
15
Nil
85
80
65
55
Nil
Nil
Nil
70
90
Nil
5
Nil Nil Nil
Nil
60
20
10
Nil
Nil
Nil
40
Nil
Nil Nil
31
© Alberto Montresor
50
Nil
85
80
65
55
Nil
Nil
Nil
90
Nil Nil Nil
Nil Nil
32
Alberi Red-Black: più colorazioni sono possibili
Alberi Red-Black: più colorazioni sono possibili
Albero Red-Black con 3 nodi neri lungo ogni percorso dalla
radice ai nodi Nil
Albero Red-Black con 3 nodi neri lungo ogni percorso dalla
radice ai nodi Nil
30
30
15
Nil
60
20
10
Nil
Nil
5
15
70
Nil
Nil
50
40
Nil
80
65
55
Nil
85
Nil
Nil
Nil
70
Nil Nil Nil
Nil
Nil
Nil
5
90
60
20
10
Nil
Nil
40
Nil
Nil Nil
33
© Alberto Montresor
Alberi Red-Black: colorazione diversa, altezza nera diversa
50
Nil Nil
30
15
60
20
Nil
50
Nil
© Alberto Montresor
Nil Nil Nil
34
70
Nil
Nil
Stesso albero con 2 nodi neri lungo ogni percorso dalla radice ai nodi Nil
15
Nil
Nil
© Alberto Montresor
30
Nil
Nil
90
Alberi Red-Black: colorazione diversa, altezza nera diversa
Albero RB con 3 nodi neri lungo ogni percorso dalla radice ai nodi Nil
10
80
65
55
Nil
85
85
80
65
Nil
Nil
Nil
Nil
70
Nil
90
Nil Nil Nil
35
60
20
10
Nil
Nil
Nil
50
Nil
© Alberto Montresor
85
80
65
Nil
Nil
Nil
Nil
90
Nil Nil Nil
36
Alberi Red-Black: questo albero può essere un albero RB?
Alberi Red-Black: questo albero può essere un albero RB?
Per vincolo sull'altezza nera ci possono essere al più 3 nodi neri lungo un percorso!
30
30
15
60
20
10
Nil
Nil
Nil
15
70
Nil
Nil
Nil
60
20
10
Nil Nil
Nil
50
40
85
70
Nil
Nil
Nil
Nil
Nil
Nil Nil
37
© Alberto Montresor
Alberi Red-Black: questo albero può essere un albero RB?
Nil Nil
Nil
50
40
55
85
55
Nil
Nil Nil
38
© Alberto Montresor
Alberi Red-Black: questo albero può essere un albero RB?
La radice è nera. Supponiamo che 60 e 70 siano entrambi neri.
30
30
15
70
Nil
Nil
Impossibile!
Perché dovremmo
violare vincolo 3
© Alberto Montresor
60
20
10
Nil
Nil
40
Nil
Nil
85
Nil
50
15
Nil
55
Nil
Quindi uno di questi
due nodi deve essere
rosso
Nil Nil
39
© Alberto Montresor
60
20
10
Nil Nil
70
Nil
Nil
40
85
Nil
50
Nil Nil
55
Nil Nil Nil Nil
40
Alberi Red-Black: questo albero può essere un albero RB?
Alberi Red-Black: questo albero può essere un albero RB?
Proviamo a colorare di rosso il nodo 60.
Esiste un percorso con 2 nodi neri
Esiste un percorso con 3 nodi neri
Impossibile per il
vincolo sulla lunghezza
30
30
15
70
Nil
Nil
15
60
20
10
Nil
Proviamo a colorare di rosso il nodo 70
Nil
Nil
60
20
10
Nil Nil
Nil
50
40
85
70
Nil
Nil
Nil
55
Nil Nil Nil Nil
41
© Alberto Montresor
Alberi Red-Black: questo albero può essere un albero RB?
Nil Nil Nil Nil
42
© Alberto Montresor
Per vincolo 4 e il vincolo 3, ci possono essere al più 2 nodi
neri lungo un percorso!
30
30
15
Nil
Nil
60
Nil
Nil
Nil
Nil
85
Nil
50
40
© Alberto Montresor
15
70
20
55
Alberi Red-Black: questo albero può essere un albero RB?
Per vincolo 4 e il vincolo 3, ci possono essere al più 2 nodi
neri lungo un percorso!
10
Nil Nil
Nil
50
40
Esistono due percorsi
con 2 soli nodi neri
85
70
Nil Nil
Nil
55
60
20
10
Nil
Nil
Nil
Nil
Nil Nil
43
© Alberto Montresor
Nil
50
40
Questa sarebbe
l’unica possibilità!
Nil
85
55
Nil Nil
Nil Nil
Impossibile!
Perché dovremmo
violare vincolo 1
44
un
nodoQuindi,
u (escluso)
unalaqualsiasi
foglia
altezza nera di u ed è indicato con b(u).
il
livello
di
un nodo
u,advale
seguente
proprietà:
interni.
il sottoalbero
con
radice
in uèhadetto
almeno:
Questo valore è ben definito in quanto tutti i percorsi di questo tipo hanno lo stesso numero di
Alberi Red-Black: Proprietà
1
(u) : u.left
= L’altezza
v.right
nil}
⇥12 ·radice
min{
: u.left
v.right
= nil}
1=
+nera
2b(u)della
1 + 1è(u)
=detta
2b(u)
1= nera
nodi nerimax{
per il vincolo
(V24b(u)
).
altezza
dell’albero.
Alberi Red-Black: questo albero può essere un albero RB?
Dimostrazione.
noti
innanzitutto
cheunessun
percorso
due nodi
rossi in fila, a
nodi interni.
completa
la dimostrazione.
Teorema
6.1.Questo
Il Si
sottoalbero
con
radice
contiene
almenopuò
2b(u)avere
1 nodi
interni.
causa del vincolo (V3 ). Tutti i cammini semplici radice-foglia hanno lo stesso numero di nodi
Teorema
LaSilunghezza
delcorto
più lungo
cammino
semplice
radice-foglia
non supera
illungo
dopDimostrazione.
per
induzione
h dell’albero
nera).
neri per il6.2.
vincolo
(procede
V 4 ); il più
di essisull’altezza
è composto
da soli
nodi(non
neri,sull’altezza
mentre
il più
pio
della
lunghezza
del
più
corto
cammino
semplice
radice-foglia.
Più
formalmente,
detto
Nelnodi
casorossi
base,e hneri,
= 0.
Alloraèulungo
deve al
essere
una foglia
nil e il sottoalbero con radice in(u)
u
alterna
e quindi
massimo
il doppio.
Figura
6.4:
Rotazione
a u,
sinistra
a la
partire
dal nodoproprietà:
x. (a)
b(u)
0 Situazione iniziale. (b) Situazione finale.
il
livello
di
un
nodo
vale
seguente
contiene esattamente almeno 2
1=2
1 = 0 nodi interni.
L’albero
nonh è>quindi
perfettamente
bilanciato,
l’altezza
dell’albero
Nel passorisultante
induttivo,
1. Allora
u è un nodo
internotuttavia
con due
figli. Ogni
figlio resta
v ha
max{
(u) : u.left = v.right = nil} ⇥ 2 · min{ (u) : u.left = v.right = nil}
comunque
limitata:
un’altezza nera b(v) pari a b(u) o a b(u) 1, a seconda del suo colore (se rosso: b(u), se nero:
Si parla di rotazione sinistra o destra, a seconda della direzione in cui i nodi vengonob(u) 1
b(u)
1). 6.3.
Usando
induttiva,
possiamo
che
ogni
figlio
ha
almeno
2 rossi+in1).1fila,
nodia
Dimostrazione.
Si l’ipotesi
noti innanzitutto
nessundire
percorso
può
avere
due
Teorema
L’altezza
di un
albero che
rosso-nero
con
n nodi
interni
è al
piùnodi
2 log(n
Questo albero NON può essere un albero Red-Black!
30
15
70
Nil
60
20
10
Nil
Nil
Nil
Nil
Nil
50
40
Nil
85
spostati. La Fig. 6.4 illustra una rotazione sinistra a partire dal nodo x; la rotazione destra è
causa delL’idea
vincolo
(V3 ). xTutti
radice-foglia
hanno lo stesso numero di nodi
speculare.
è spostare
versoi ilcammini
basso e y semplici
verso l’alto;
per farlo, bisogna:
Dimostrazione.
Per(Vil );Teorema
6.1, l’albero ha almeno n ⇤ 2b(r) 1, dove r è la radice.
neri per il vincolo
4 il più corto di essi è composto da soli nodi neri, mentre il più lungo
✦
L’altezza
dell’albero
èB al
il doppio
dell’altezza
della radice (come detto sopra, ogni
(1)
spostare
il segue:
sottoalbero
come
figlio
x; massimonera
Da cui
alterna
nodi
rossi e neri,
e più
quindi
èdestro
lungodi
al
il doppio.
(2)
far diventare
x il essere
figlio sinistro
di y;
nodo
rosso
deve
seguito
da
uno
nero),
e
quindi
n
⇤
2h/2 1. Semplificando, si ottiene
✦ Le operazioni di ricerca hanno costo O(log n)
h/2
(3)
far
diventare
y
figlio
di
p,
il
vecchio
padre
di
x.
non è quindi
perfettamente
bilanciato,
tuttavia
l’altezza dell’albero
n +L’albero
1 ⇤ 2 risultante
e applicando
il logaritmo
ad entrambi
i lati della
disequazione
si ottiene resta
h⇥
✦
comunque
limitata:
2 log(n Cosa
+ 1). succede per le operazioni di modifica?
Si noti che le proprietà dell’ABR non vengono violate. Infatti, i sottoalberi A e C restano
Nil Nil
55
Nil Nil
45
© Alberto Montresor
Inserimenti
✦
è possibile che le condizioni di bilanciamento risultino violate.
x.right
y.left
% Il sottoalbero B diventa figlio destro di x
chiedono
alcuna
modifica rispetto al normale
comportamento degli alberi binari di ricerca.
–ifcambi
in cui la variabile
color viene mutata;
y.left ⇥=dinilcolore,
then y.left.parent
x
Tuttavia,
gli
inserimenti
o
le
cancellazioni
possono
violare
i vincoli
Red-Black;
ripristinare
(2)–y.left
x in cui la struttura dell’albero binario%dix ricerca
diventa figlio
di y senza tuttavia
rotazioni,
vienesinistro
cambiata,
tali
vincoli
può
richiedere
una
quantità
O(log
n)
di
modifiche
all’albero,
ognuna
delle quali
(2) x.parent
violare leyproprietà di ordinamento di tali alberi.
con
costo
O(1).
Nel
seguito
illustreremo
come
effettuare
le
modifiche,
illustrando
solo infor(3) y.parent
p
% y diventa figlio di p
(3)
if
p
=
⇥
nil
then
malmente
la loromuovono
correttezza:
per i “verso
dettaglil’alto”
precisi
e lenodo
dimostrazioni
formalilo(molto
Le rotazioni
un nodo
e un
“verso il basso”;
scopo lunghe
è ridurree
if p.left = x then p.left
y else p.right
y
macchinose)
si faccia
riferimento
agli articoli
originali.
lo
sbilanciamento
dell’albero,
scegliendo
una
coppia
di
nodi
tali
per
cui
il
nodo
spostato
in alto
p
return y
Leun
modifiche
possono
essere maggiore
di due tipi:
abbia
sottoalbero
con altezza
del sottoalbero del nodo spostato in basso.
(1)
(1)
Quando le proprietà Red-Black vengono violate si può agire:
✦
modificando i colori nella zona della violazione;
✦
operando dei ribilanciamenti dell’albero tramite rotazioni:
✦
Rotazione destra
✦
Rotazione sinistra
46
con costo O(1). Nel seguito illustreremo come effettuare le modifiche, illustrando solo informalmente
lagarantisce
loro
correttezza:
dettagli precisi
e le dimostrazioni
(molto lunghe
Questo
le ioperazioni
di ricerca,
inserimento eformali
cancellazione
possonoe
T REE
rotateLeft
(T REE
x)che tutteper
macchinose)
si
faccia
riferimento
agli
articoli
originali.
T REEcompletate
y
x.right in tempo O(log n), dove n è il numero di nodi.
essere
Le
possono
essere
due tipi:
TLe
REEmodifiche
p
x.parent
operazioni
lookupNode
(), di
successorNode
(), predecessorNode(), min() e max() non ri-
Durante la modifica di un albero Red-Black:
✦
✦
figli sinistro di x e destro di y, rispettivamente; x diventa figlio sinistro di y, senza causare
Teorema
L’altezza
di tutte
un albero
rosso-nero
n nodi
interni è al
più 2 log(n + possono
1).
Questo6.3.
garantisce
che
le operazioni
di con
ricerca,
inserimento
e cancellazione
problemi in quanto la chiave in x è minore della chiave in y; infine, le chiavi contenuti in B
essere
completate
in
tempo
O(log
n),
dove
n
è
il
numero
di
nodi.
sono
maggiori della Per
chiave
x, e vengono
di x. r è la radice.
Dimostrazione.
il inTeorema
6.1,correttamente
l’albero ha spostate
almenonelnsottoalbero
⇤ 2b(r) destro
1, dove
Le
operazioni
lookupNode
(), successorNode
(), predecessorNode
min
() e max() non riIl
codice
associato
a
queste
operazioni
è
illustrato
nella
procedura
rotateLeft(); le(),
righe
L’altezza dell’albero è al più il doppio dell’altezza nera della radice (comesono
detto sopra, ogni
chiedono
alcuna
rispettole al
normale comportamento
degli alberi
binari di ricerca.
marcate
con (1),
(2) e modifica
(3) per identificare
corrispondenti
operazioni. Lah/2
procedura
restituisce
nodo
rosso
deve
essere
seguito
da uno nero), e quindi
n ⇤ 2 O(1);
1. la
Semplificando,
si ottiene
Alberto
il©Tuttavia,
nodoMontresor
che ha
sostituito
x, ovvero
Il costo di una rotazione
rotazione
glih/2
inserimenti
o ley.cancellazioni
possonoè ovviamente
violare i vincoli
Red-Black;
ripristinare
n
+
1
⇤
2
e
applicando
il
logaritmo
ad
entrambi
i
lati
della
disequazione
si
ottiene
h⇥
destra
rotateRight
può essere ottenuta
semplicemente
scambiando
fra loroall’albero,
ogni occorrenza
tali vincoli
può() richiedere
una quantità
O(log n)
di modifiche
ognuna delle quali
2
log(n
+
1).
delle
variabili leftaesinistra
right.
Rotazione
✦
Operazioni
– cambi di colore, in cui la variabile color viene mutata;
x
– (1)
rotazioni,
in cui la
dell’albero
far diventare
B struttura
figlio destro
di x binario di ricerca viene cambiata, senza tuttavia
violare le proprietà di ordinamento di tali alberi.
(2) far diventare x il figlio sinistro di y
A
y
Le rotazioni muovono un nodo “verso l’alto” e un nodo “verso il basso”; lo scopo è ridurre
(3) far diventare
y figlio di
p, il vecchio
padredidinodi
x tali per cui il nodo spostato in alto
lo sbilanciamento
dell’albero,
scegliendo
una coppia
B
C
abbia un sottoalbero con altezza maggiore del sottoalbero del nodo spostato in basso.
© Alberto Montresor
47
© Alberto Montresor
48
destra rotateRight() può essere ottenuta semplicemente scambiando fra loro ogni occorrenza
delle
variabili leftaesinistra
right.
Rotazione
destra rotateRight() può essere ottenuta semplicemente scambiando fra loro ogni occorrenza
delle
variabili leftaesinistra
right.
Rotazione
T REE rotateLeft(T REE x)
T REE y
x.right
T REE p
x.parent
(1) x.right
y.left
% Il sottoalbero B diventa figlio destro di x
(1) if y.left ⇥= nil then y.left.parent
x
(2) y.left
x
% x diventa figlio sinistro di y
(2) x.parent
y
(3) y.parent
p
% y diventa figlio di p
(3) if p ⇥= nil then
if p.left = x then p.left
y else p.right
y
return y
T REE rotateLeft(T REE x)
T REE y
x.right
T REE p
x.parent
(1) x.right
y.left
% Il sottoalbero B diventa figlio destro di x
(1) if y.left ⇥= nil then y.left.parent
x
(2) y.left
x
% x diventa figlio sinistro di y
(2) x.parent
y
(3) y.parent
p
% y diventa figlio di p
(3) if p ⇥= nil then
if p.left = x then p.left
y else p.right
y
return y
✦
Operazioni
p
y
✦
(1) far diventare B figlio destro di x
x
A
C
(3) far diventare y figlio di p, il vecchio padre di x
49
Inserimento in alberi Red-Black
✦
Coloriamo il nuovo nodo di rosso
✦
Quale delle quattro proprietà può essere violata?
T REE p
nil
T REE u
T
while u ⇥= nil and u.key ⇥= x do
p
u
u
iif(x < u.key, u.left, u.right)
if u ⇥= nil and u.key = x then
u.value
v
else
T REE n
Tree(x, v)
link(p, n, x)
if p = nil then return n
Ripasso:
✦
la radice è nera
✦
i nodi Nil sono neri;
✦
se un nodo è rosso, allora entrambi i suoi figli sono neri;
✦
ogni percorso da un nodo interno ad una foglia ha lo stesso numero di nodi neri
© Alberto Montresor
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
B
101
50
T REE insertNode(T REE T, I TEM x, I TEM v)
Ricerca della posizione usando la stessa procedura usata per gli alberi binari di
ricerca
✦
© Alberto Montresor
A
C
Come modificare la insertNode()
Inserimento
✦
x
(2) far diventare x il figlio sinistro di y
B
© Alberto Montresor
✦
y
(1) far diventare B figlio destro di x
(2) far diventare x il figlio sinistro di y
(3) far diventare y figlio di p, il vecchio padre di x
Operazioni
p
return T
51
% Padre
% Cerca posizione inserimento
% Chiave già presente
balanceInsert(n)
% Primo nodo ad essere inserito
% Ritorna albero non modificato
confrontato con il contenuto del padre. Come casi particolari, p può essere nil, che significa
che u è la nuova radice; oppure u può essere nil, che significa che un nodo è stato cancellato e
52
© Alberto Montresor
nil sostituisce il figlio corrispondente nel padre. link() ha costo O(1).
Inserimento in alberi Red-Black
✦
Come sistemare:
✦
✦
✦
✦
Ci spostiamo verso l’alto lungo il percorso di inserimento
per ripristinare la proprietà 3 (red-black)
✦
✦
balanceNode(Tree t)
spostando le violazioni verso l’alto rispettando il vincolo 4 (mantenendo
l’altezza nera dell’albero)
Al termine, coloriamo la radice di nero
Caso 1:
✦
Nuovo nodo t non ha padre
Caso 2
✦
Padre p di t è nero
✦
Nessun vincolo violato 109
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
nodo BILANCIATI
ad essere inserito
o
CAPITOLOPrimo
6. ALBERI
DI RICERCA
siamo risaliti fino alla radice
✦
✦
Suo padre p
p
t
z
111
t.color
RED
110 while t 6= nil do
Algoritmi e Strutture di Dati
T REE p
t.parent
% Padre
T REE n
iif(p 6= nil, p.parent, nil)
% Nonno
Dobbiamo quindi porre t = p ed eseguire un’ulteriore (ultima) iterazione del ciclo. Si noti
T REE z
iif(n = nil, nil, iif(n.left = p, n.right, n.left))
% Zio
che alcuni cammini radice-foglia sono ora instradati diversamente; ma i nodi coinvolti nel
if p = nil then
% Caso (1)
cambiamento
sono pBLACK
e t, entrambi rossi, quindi la lunghezza dei cammini neri non cambia.
t.color
Il caso (4b)
è
speculare
a (4a), con t figlio sinistro di p e p figlio destro di n; in questo caso
t
nil
è necessaria
una rotazione
a destra.
else if p.color
= BLACK
then
% Caso (2)
53
Montresor
t infine
nil che t sia figlio sinistro di p e p sia figlio sinistro di n. Una rotazione54
(5a),(5b)© Alberto
Si assuma
elseaifpartire
z.colorda=nRED
then ad una situazione in cui t e n sono figli di %
(3)
a destra
ci porta
p; Caso
colorando
Inserimento
- 7 casiz.color
possibili BLACK
p.color
n di rosso e p di nero ci troviamo in una situazione in cui tutti i vincoli Red-Black sono
RED
rispettati;n.color
in particolare,
la lunghezza di tutti i cammini neri che passano per la radice è
✦ Caso 1:t
✦ Caso 2
n
uguale alla situazione iniziale. Il caso (5b) è speculare
a (5a), con t figlio destro di p e p
else
✦ Nuovo
✦ Padre apsinistra.
figlio
destro
di
n;
in
questo
caso
è
necessaria
una
rotazione
nodo
t
non
ha
padre
di t è nero % Caso (4.a)
if (t = p.right) and (p = n.left) then
109
#
#
#<!"#
$'&
#<!"#
$-.&
#
,
"
© Alberto Montresor
!
"
!
"
rotateLeft
(p) inserito
✦ Nessun vincolo violato
Primo nodo
ad essere
t
p
balanceInsert
(T REE t)
✦ Si colora
else if t(tdi=nero
p.left) and (p = n.right) then
% Caso (4.b)
t.color
RED
rotateRight(p)
while
! t ⇥= niltdo p
T REEelse
p
t.parent
% Padre
T REE n if (t
iif(p.parent
=
⇥
nil,
p.parent,
nil)
%
Nonno
= p.left) and (p = n.left) then
% Caso
(5.a)
T REE z
iifrotateRight
(n = nil, nil,
% Zio
(n)iif(n.left = p, right, left))
if p = nilelse
thenif (t = p.right) and (p = n.right) then
Caso
(1)
%%Caso
(5.b)
t.color rotateLeft
BLACK (n)
t
nil
p.color
BLACK
else if p.color
=
BLACK then
% Caso (2)
n.color
RED
t
nil
t
nil
else if z.color = RED then
% Caso (3)
p.color
z.color
BLACK
n.color
RED
La
complessità
© Alberto
Montresor
t
n della procedura balanceInsert() è O(h), dove h è l’altezza dell’albero. In-56
✦
Si colora t di nero
(
!$%&
✦
n
Le operazioni di ripristino sono necessarie solo quando due nodi consecutivi sono
rossi!
Inserimento - 7 casi possibili
✦
Il nodo inserito t
balanceInsert(T REE t)
© Alberto Montresor
✦
✦
✦ Suo nonno n
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
✦ Suo zio z
Nota
✦
Nodi coinvolti
!
55
Inserimento - 7 casi possibili
Inserimento - 7 casi possibili
balanceInsert(T REE t)
110 t.color
Algoritmi e Strutture di Dati
RED
✦ Se z è rosso, è possibile colorare di nero p, z, e di rosso n.
✦ Caso 3
while t ⇥= nil do
✦ Poiché tutti i cammini che passano per z e p passano per n, ✦ t rosso
✦ t rosso
✦
i cammini
che passano
per z iterazione
e p passano
n,%
SiPadre
T REE pquindit.parent
Dobbiamo
porrePoiché
t = p tutti
ed eseguire
un’ulteriore
(ultima)
delper
ciclo.
noti
la
lunghezza
dei
cammini
neri
non
è
cambiata.
la
lunghezza
dei
cammini
neri
non
è
cambiata.
✦ p rosso
✦
p rosso
T REE
n
iif(p.parent
⇥= nil,sono
p.parent,
nil)
% Nonno
che alcuni
cammini
radice-foglia
ora instradati
diversamente; ma i nodi coinvolti
nel
✦ Il problema può essere ora sul nonno:
✦
cambiamento
p e=Ilt,nil,
entrambi
rossi,
quindi
la lunghezza
T REE z sono
iif(n
nil, iif(n.left
= p, ora
right,
% Zio
problema
può essere
sulleft))
nonno: dei cammini neri non cambia.
✦ z rosso
✦ z rosso
✦ violato vincolo (1), ovvero n può essere una radice rossa
Il caso
è speculare
a✦ (4a),
con
t
figlio
sinistro
di
p
e
p
figlio
destro
di
n;
in
questo
if p(4b)
= nil
then
%
Caso
(1)
violato vincolo (1), ovvero n può essere una radice rossa caso
✦ violato vincolo (3), ovvero n rosso può avere un padre
t.color
BLACK
è necessaria una rotazione
a destra.
✦ violato vincolo (3), ovvero n rosso può avere un padre rosso.
t infine
nil che t sia figlio sinistro di p e p sia figlio sinistro di n. Una rotazione
rosso.
(5a),(5b) Si assuma
✦ BLACK
else aifpartire
p.colorda=
Caso (2)
tad
= una
n, e ilsituazione
ciclo continua.
✦ Poniamo t = n, e il ciclo continua.
a destra
nPoniamo
ci portathen
in cui t e n sono figli di p;%colorando
t
nil
n di rosso e p di nero ci troviamo in una situazione in cui tutti i vincoli Red-Black sono
#<*
*
*
else if z.color = RED then
% Caso (3)
rispettati; in particolare, la lunghezza di tutti i cammini neri che passano per la radice è
p.color
z.color
BLACK
CAPITOLO 6. ALBERI
BILANCIATI
DI RICERCA (
109
(
+
+
uguale alla situazione iniziale. Il caso (5b) è speculare a (5a), con t figlio destro di p e p
n.color
RED
figlio destro di n; in questo caso è necessaria una rotazione a sinistra.
$)&
#
#
t
n
else
,
0
/
,
0
/
if (t(T=REE
p.right)
and (p = n.left) then
% Caso (4.a)
balanceInsert
t)
"
!
"
!
n.left
rotateLeft(p)
t.color
RED
t
p
while t ⇥= nil do
57
© Alberto Montresor
© Alberto Montresorelse if (t = p.left) and (p = n.right) then
% Caso (4.b)58
T REE p
t.parent
% Padre
n.right
rotateRight(p)
T REE n - iif7(p.parent
⇥= nil, p.parent, nil)
% Nonno
Inserimento - 7 casi possibili
Inserimento
t
pcasi possibili
T REE z
iif(n = nil, nil, iif(n.left = p, right, left))
% Zio
else
if
p
=
nil
then
%
Caso
(1)
✦ Si assuma che t sia figlio destro di p e che p sia figlio sinistro di n
✦ Si assuma
✦ Caso 4a,4b
✦ Caso 4a,4b
t sia figlio
sinistro
n
if (t =BLACK
p.left)
and (pche
= n.left)
thendestro di p e che p sia figlio%
Caso di
(5.a)
t.color
n.left
rotateRight
(n)
✦ t rosso
✦ t rosso
✦ Una rotazione a sinistra a partire dal nodo p scambia i ruoli di t e
✦ Una rotazione a sinistra a partire dal nodo p scambia i ruoli di t e
t
nil
else if=(tBLACK
= p.right)
(p = n.right) then
% Caso(2)
(5.b)
else
if
p.color
thenand
p ottenendo il caso (5a), dove i nodi rossi in conflitto sul vincolo
p ottenendo
il caso (5a), dove i nodi rossi in conflitto%sulCaso
vincolo
✦ p rosso
✦ p rosso
rotateLeft(n)
t
nil n.right
(3) sono entrambi figli sinistri dei loro padri
(3) sono entrambi figli sinistri dei loro padri
p.color
BLACK
✦ z nero
✦ z if
else
z.color
= RED
then
% Caso (3)
nero
✦ I nodi coinvolti nel cambiamento sono p e t, entrambi rossi, quindi
✦
I RED
nodi coinvolti
p.color
BLACK nel cambiamento sono p e t, entrambi rossi, quindi
n.colorz.color
la lunghezza dei cammini neri non cambia
n.color
!
t
nilREDla lunghezza dei cammini neri non cambia
t
n
else
$12&
#<(
*
*
$13&45(67892:6
if (t = p.right) and (p = n.left) then
% Caso (4.a)
n.left
rotateLeft(p)
(
+
#
+
t
p
#
(
else if (t = p.left) and (p = n.right) then
% Caso (4.b)
"
0
/
,
0
/
n.right
rotateRight(p)
t
p
!
,
"
!
Figura 6.5: Cinque dei sette possibili casi di inserimento. I casi (4b) e (5b) non sono rappresentati, in
else
quanto speculari ai casi (4a) e (5a). Il caso (2) non richiede alcuna modifica, mentre tutti gli altri casi
if (t = p.left) and (p = n.left) then
% Caso (5.a)
collegano la situazione iniziale e la situazione finale con una freccia.
n.left
rotateRight(n)
59
60
© Alberto Montresor
© Alberto Montresor
else if (t = p.right) and (p = n.right) then
% Caso (5.b)
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
✦
Caso 3
✦
109
Se z è rosso, è possibile colorare di nero p, z, e di rosso n.
else if p.color = BLACK then
✦
Caso 5a,5b
✦
t rosso
✦
p rosso
✦
z nero
✦
✦
✦
!
✦
Si assuma che t sia figlio sinistro di p e p sia figlio sinistro di n
✦
Una rotazione a destra a partire da n ci porta ad una situazione in
cui t e n sono figli di p
Colorando n di rosso e p di nero ci troviamo in una situazione in
cui tutti i vincoli Red-Black sono rispettati
!
in particolare, la lunghezza dei cammini neri che passano per la
radice è uguale alla situazione iniziale
$;2&
$;3&45(67892:6
*
(
% Caso (2)
t
nil- 7 casi possibili
Inserimento
Inserimento - 7 casi possibili
(
+
#
110
#
#<!"#
*
Algoritmi e Strutture di Dati
+
!
,porre t = p0ed eseguire/ un’ulteriore"(ultima) iterazione
, ciclo. Si noti
Dobbiamo quindi
del
che alcuni cammini radice-foglia sono ora instradati diversamente; ma i nodi coinvolti nel
cambiamento
sono p e t, entrambi rossi, quindi la lunghezza dei cammini neri non cambia.
"
!
0
/
Il caso (4b) è speculare a (4a), con t figlio sinistro di p e p figlio destro di n; in questo caso
è necessaria una rotazione a destra.
(5a),(5b) Si assuma infine che t sia figlio sinistro di p e p sia figlio sinistro di n. Una rotazione
a destra a partire da n ci porta ad una situazione in cui t e n sono figli di p; colorando
n di dei
rossosette
e p dipossibili
nero ci troviamo
una situazione inI cui
tutti
i vincoli
Red-Black
sonorappresentati, in
Figura 6.5: Cinque
casi diin inserimento.
casi
(4b)
e (5b)
non sono
© Alberto Montresor
in particolare, la lunghezza di tutti i cammini neri che passano per la radice è
quanto specularirispettati;
ai casi (4a)
e (5a). Il caso (2) non richiede alcuna modifica, mentre tutti gli altri casi
uguale alla situazione iniziale. Il caso (5b) è speculare a (5a), con t figlio destro di p e p
collegano la situazione
iniziale
la situazione
finale con
una freccia.
figlio destro
di n; ine questo
caso è necessaria
una rotazione
a sinistra.
61
All together, now!
else if z.color = RED then
% Caso (3)
p.color
z.color
BLACK
✦ Si assuma che t sia figlio sinistro di p e p sia figlio sinistro di n
Caso 5a,5b
n.color
RED
✦ t rosso
✦ Una rotazione a destra a partire da n ci porta ad una situazione in
t
n
else
cui t e n sono figli di p
✦ p rosso
if (t = p.right) and (p = n.left) then
% Caso (4.a)
✦ Colorando n di rosso e p di nero ci troviamo in una situazione in
✦ z nero
n.left
rotateLeft(p)
cui tutti i vincoli Red-Black sono rispettati
t
p
else if (t = p.left)
and (p = n.right) then
% Caso (4.b)
✦ in particolare, la lunghezza dei cammini neri che passano per la
n.right
rotateRight(p)
radice è uguale alla situazione iniziale
t
p
else
if (t = p.left) and (p = n.left) then
% Caso (5.a)
n.left
rotateRight(n)
else if (t = p.right) and (p = n.right) then
% Caso (5.b)
n.right
rotateLeft(n)
p.color
BLACK
n.color
RED
t
nil
62
© Alberto Montresor
Inserimento in alberi Red-Black
T
balanceInsert(T REE t)
t.color
RED
while t ⇥= nil do
T REE p
t.parent
T REE n
iif(p ⇥= nil, p.parent, nil)
T REE z
iif(n = nil, nil, iif(n.left = p, n.right, n.left))
if p = nil then
t.color
BLACK
t
nil
else if p.color = BLACK then
t
nil
else if z.color = RED then
p.color
z.color
BLACK
n.color
RED
t
n
else
if (t = p.right) and (p = n.left) then
rotateLeft(p)
t
p
else if (t = p.left) and (p = n.right) then
rotateRight(p)
t
p
else
if (t = p.left) and (p = n.left) then
rotateRight(n)
else if (t = p.right) and (p = n.right) then
rotateLeft(n)
p.color
BLACK
n.color
RED
t
nil
© Alberto Montresor
t
30
% Padre
% Nonno
% Zio
% Caso (1)
15
16
Nil
70
Nil
% Caso (2)
Nil
% Caso (4.a)
60
20
10
% Caso (3)
Nil
Nil
Nil
% Caso (4.b)
50
40
% Caso (5.a)
Nil
Nil
85
80
65
55
Nil
Nil
Nil
90
Nil Nil Nil
Nil Nil
% Caso (5.b)
63
© Alberto Montresor
64
Inserimento in alberi Red-Black
Inserimento in alberi Red-Black:
T
p è nero, t è rosso
T
30
15
70
Nil
Nil
t 16
Nil
Nil
50
Nil
55
Nil
85
80
65
40
Nil
Caso 2: nessun cambiamento
Non cambia l’altezza nera
di nessun nodo!
15
60
20
10
Nil
Nil
Nil
Nil
90
30
80
65
55
Nil
85
Nil
Nil
Nil
90
Nil Nil Nil
Nil Nil
66
© Alberto Montresor
T
p è rosso, t è rosso
30
70
15
60
20
85
50
Nil
Nil Nil Nil
Coloriamo di nero p
Coloriamo di nero z
Coloriamo di rosso n
z
p
40
55
Nil
Nil
Nil
t
Nil
Nil
42
60
20
90
80
65
70
10
n
Nil
Vincolo 3 è violato
© Alberto Montresor
40
Nil
T
15
Caso 3: z è rosso
50
Nil
Inserimento in alberi Red-Black
p è rosso, t è rosso
Nil
Nil
Nil Nil
Inserimento in alberi Red-Black
Nil
Nil
Nil Nil Nil
65
Nil
60
20
Nil
Nil
70
10
© Alberto Montresor
10
x 42
30
Nil
Nil
n
Nil
50
Nil
40
© Alberto Montresor
90
55
Nil
Nil
Nil
Nil Nil Nil
t
Nil
67
80
65
z
p
Nil
Nil Nil
85
42
Nil Nil
Nil
68
Inserimento in alberi Red-Black
Inserimento in alberi Red-Black
T
p è rosso, t è rosso
T
p è rosso, t è rosso
30
30
Caso 5a: z è nero
15
70
15
70
n
p
Nil
60
20
10
85
t
Nil
Nil
Nil
Vincolo 3 è ripristinato
Altri vincoli mai stati
violati
50
40
Nil
Il padre del padre
di t è il nuovo t
55
42
Nil
80
65
Nil
Nil
Nil
Nil
90
Nil Nil Nil
Nil Nil
60
20
10
Nil
Nil
Nil
50
40
Vincolo 3 è nuovamente violato
tra il nuovo t e suo padre
Nil
Inserimento in alberi Red-Black
T
Nil
Nil
Nil Nil Nil
Nil Nil
42
Nil
70
© Alberto Montresor
T
p è rosso, t è rosso
30
Caso 5a: z è nero
30
Caso 5a: z è nero
15
70
15
60
t
Nil
Coloriamo di nero t
Coloriamo di rosso n
Rotazione sinistra
Nil
60
x
20
10
Nil
50
40
Nil
Nil
© Alberto Montresor
Nil
90
Inserimento in alberi Red-Black
p è rosso, t è rosso
Nil
80
65
55
Nil
69
85
t
Nil
© Alberto Montresor
z
80
65
55
42
85
Nil
Nil
Nil
Nil
90
Nil Nil Nil
Vincolo 3 è ripristinato
Altri vincoli mai stati
violati
Abbiamo finito
Nil Nil
Nil
Nil
70
50
20
10
40
Nil
Nil
Nil
55
42
Nil
85
65
Nil Nil Nil Nil
Nil
80
90
Nil Nil Nil
Nil
71
© Alberto Montresor
72
Inserimento in alberi Red-Black
Inserimento: complessità
T
✦
30
15
60
x
Nil
Nil
L’unico caso un cui si procede a
ripristinare verso l’alto è il caso
3. Negli altri casi, si esce dal
while e si termina
40
Nil
Nil
Nil
55
42
Nil
85
65
Nil Nil Nil Nil
Nil
80
✦
O(1) per effettuare l'inserimento
73
Esiste anche la possibilità di effettuare una “top-down” insertion
✦
Scendere fino al punto di inserimento, “aggiustando” l'albero mano a mano
✦
Effettuare l'inserimento in una foglia
© Alberto Montresor
74
Cancellazione in RB
L’algoritmo di cancellazione per alberi RB è costruito sull’algoritmo di
cancellazione per alberi binari di ricerca
✦
Dopo la cancellazione si deve decidere se è necessario ribilanciare o meno
Le operazioni di ripristino del bilanciamento sono necessarie solo quando il nodo
cancellato è nero! (perché?)
✦
Se il nodo “cancellato” è rosso
✦
altezza nera invariata
✦
non sono stati creati nodi rossi consecutivi
✦
la radice resta nera
Se il nodo “cancellato” è nero
✦
✦
✦
✦
75
possiamo violare il vincolo 1: la radice può essere un nodo rosso
possiamo violare il vincolo 3: se il padre e uno dei figli del nodo
cancellato erano rossi
abbiamo violato il vincolo 4: altezza nera cambiata
L’algoritmo balanceDelete(T,t) ripristina la proprietà Red-Black con rotazioni
e cambiamenti di colore:
✦
© Alberto Montresor
O(log n) per risalire e “aggiustare”
(caso pessimo – solo nel caso 3)
Nil Nil Nil
Cancellazione in RB
✦
✦
90
© Alberto Montresor
✦
O(log n) per scendere fino al punto di inserimento
70
✦
Nil
✦
✦
50
20
10
Totale: O(log n)
ci sono 4 casi possibili (e 4 simmetrici)!
© Alberto Montresor
76
102
Algoritmi e Strutture di Dati
Cancellazione
Cancellazione - 8 casi possibili
T REE removeNode(T REE T, I TEM x)
112
Algoritmi e Strutture di Dati
T REE u
lookupNode(T, x)
if u ⇥= nil then
if u.left ⇥= nil and u.right ⇥= nil then
% Caso 3
T REE s
u.right
while s.left ⇥= nil do s
s.left
u.key
s.key
u.value
s.value
u
s
T REE t
if u.left ⇥= nil and u.right = nil then
% Caso (2) - Solo figlio sx
t
u.left
else
% Caso (2) - Solo figlio dx / Caso (1)
t
u.right
link(u.parent, t, x)
if u.color = BLACK then balanceDelete(T, t)
if u.parent = nil then T = t
delete u
return T
77
© Alberto Montresor
Cancellazione - 8 casi possibili
– il caso (2) con solo un figlio sinistro è semplice; il figlio sinistro viene collegato al padre di
u; se-:/il padre è assente,
u era radice e il suo figlio sinistro
diventa la nuova radice.
#
#
– il caso (2) con solo un figlio destro è"12%34"563"7
simmetrico; il figlio destro viene collegato al padre di
"
$ radice e il suo figlio
"
%&
u; se il padre
è assente, u era
destro diventa
la nuova radice. Si noti
che in pratica questo %&
codice gestisce
anche il caso (1), dove però il $ figlio destro di u è nil.
%'
Se sia u che il suo figlio destro sono nil, l’albero è ora vuoto e la nuova radice diventa per
!
(
!
*
(
%'
l’appunto nil.
*
)
,
+
)
La memoria associata al nodo u viene rimossa e la radice (potenzialmente
modificata)
vie,
+
ne restituita al chiamante. Richiedendo al massimo una discesa radice-foglia, anche questa
-;/ ha costo O(h).
procedura
$
#
A differenza delle tabelle hash che verranno
presentate
nel
prossimo
capitolo, gli alberi
"1<1=
#
%'
"
$
di ricerca mantengono l’ordinamento fra i valori. Un operatore min() che restituisca
il nodo
contenente il minimo può%&essere realizzato
facilmente
in tempo %&
O(h). Basta infatti effettuare
"
%'
una ricerca in cui si segue sempre il figlio sinistro, fino a trovare un nodo che non ha figlio
,
+
!
(
sinistro. L’operatore max() è simmetrico, basta seguire sempre il figlio destro.
*
T REE min(T REE T )
)
,
+
!
(
*
)
T REE max(T REE T )
79
Figura
6.6:
Quatto
degli
otto
possibili
casi
di
cancellazione,
gliwhile
altri sono
speculari.
Tutti
while T.left ⇥= nil do
T.right
⇥= nil
doi casi collegano
© Alberto Montresor
-./
$
#
"
"12%34"563"7
$
%&
!
#
%'
"
%'
%&
,
(
*
-0/
)
,
+
!
"
$
#
$
%'
%&
!
(
CAPITOLO 6. ALBERI BILANCIATI DI RICERCA
)
)
"
%&
*
*
%87971"
#
!
(
,
+
+
%'
(
113
*
)
,
+
78
© Alberto Montresor
Cancellazione in RB
balanceDelete(T REE T , T REE t)
while t ⇥= T and t.color = BLACK do
T REE p
t.parent
% Padre
if t = p.left() then
T REE f
p.right
% Fratello
T REE ns
f.left
% Nipote sinistro
T REE nd
f.right
% Nipote destro
if f.color = RED then
% (1)
p.color
RED
f.color
BLACK
rotateLeft(p)
% t viene lasciato inalterato, quindi si ricade nei casi 2,3,4
else
if ns.color = nd.color = BLACK then
% (2)
f.color
RED
t
p
else if ns.color = RED and nd.color = BLACK then
% (3)
ns.color
BLACK
f.color
RED
rotateRight(f )
% t viene lasciato inalterato, quindi si ricade nel caso 4
else if nd.color = RED then
% (4)
f.color
p.color
p.color
BLACK
nd.color
BLACK
rotateLeft(p)
t
nil
Figura 6.6: Quatto degli otto possibili casi di cancellazione, gli altri sono speculari. Tutti i casi collegano
else
% Casi (5)-(8)
speculari
a (1)-(4)
la situazione
iniziale
e la
situazione finale con una freccia.
if t ⇥= nil then t.color
© Alberto Montresor
BLACK
80
Cancellazione in RB
✦
L’operazione di cancellazione è concettualmente complicata!
✦
Ma efficiente:
✦
Dal caso (1) si passa ad uno dei casi (2), (3), (4)
✦
Dal caso (2) si torna ad uno degli altri casi, ma risalendo di un livello l’albero
✦
Dal caso (3) si passa al caso (4)
✦
Nel caso (4) si termina
Esercizi
✦
Esercizio - visita non ricorsiva
✦
✦
✦
✦
✦
✦
In altre parole, è possibile visitare al massimo un numero O(log n) di casi, ognuno dei quali è gestito in tempo O(1)
81
Dimostrate che se un nodo in un ABR ha due figli, allora il suo successore non ha
un figlio sinistro e il suo predecessore non ha un figlio destro
Esercizio
✦
© Alberto Montresor
Dimostrare: poiché l'ordinamento basato su confronti di n elementi è Ω(n log n),
allora qualunque algoritmo basato su confronti per costruire un ABR è Ω(n log n)
Esercizio - proprietà albero
✦
✦
Qual è la sua complessità
Esercizio - limite inferiore
✦
Quindi
Scrivere l’algoritmo non ricorsivo che effettua un attraversamento in ordine di un
ABR
L'operazione di cancellazione è commutativa? Nel senso che cancellare x e y
oppure cancellare y e x produce lo stesso ABR?
© Alberto Montresor
82