! ! 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