Sommario Università di Torino – Facoltà di Scienze MFN Corso di Studi in Informatica Curriculum SR (Sistemi e Reti) • Alberi binari 1-bilanciati in altezza e loro proprietà. • Alberi AVL = alberi binari di ricerca 1-bilanciati in altezza. • Operazioni di inserimento e cancellazione in alberi AVL: • rotazioni di ribilanciamento; • analisi della complessità. Algoritmi e Laboratorio a.a. 2009-10 Lezioni prof. Elio Giovannetti Lezione 35 – Alberi AVL versione 21/01/10 Quest' opera è pubblicata sotto una Licenza Creative Commons Attribution-NonCommercial-ShareAlike 2.5. 21/01/10 21.23 Alberi bilanciati in altezza • Nota: la denominazione è appropriata, poiché si dimostra facilmente che gli alberi bilanciati in altezza sono bilanciati, cioè che al crescere del numero n dei nodi la loro altezza cresce come Θ(log n) (vedi dimostrazione più avanti). E. Giovannetti - AlgELab-09-10 - Lez.35 3 Alberi 1-bilanciati col minimo numero di nodi. Base: Gli alberi 1-bilanciati di altezza 0 o 1 di dimensione minima, cioè aventi il numero minimo di nodi sono: h=0 n0 = 1 h=1 n1 = 2 oppure Passo: L'albero 1-bilanciato di altezza h di dimensione minima è un albero lb d della ll f forma sottostante tt t t o sua speculare: l nh = 1 + nh-1 + nh-2 h h-1 T1 T2 2 Alberi bilanciati in altezza. Definizione non induttiva • albero binario k-bilanciato (in altezza): in ogni nodo l'altezza del figlio sinistro e quella del figlio destro differiscono al più di k; in particolare: • albero binario 1-bilanciato (in altezza): in ogni nodo l'altezza del figlio sinistro e quella del figlio destro differiscono al più di 1; 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 h-2 dove T1 e T2 sono alberi 1-bilanciati di dimensione minima di altezze rispettivamente e h-2.- Lez.35 21/01/10 21.23 E. Giovannetti h-1 - AlgELab-09-10 5 Definizione induttiva, equivalente alla precedente • Un albero vuoto (o di un solo elemento) è k-bilanciato. • Un albero (T1 el T2) è k-bilanciato se: • T1 è k-bilanciato; • T2 è k-bilanciato; • le altezze di T1 e T2 differiscono al più di k. e ovviamente, in particolare: • Un albero vuoto (o di un solo elemento) è 1-bilanciato. • Un albero (T1 el T2) è 1-bilanciato se: • T1 è 1-bilanciato; • T2 è 1-bilanciato; • le altezze di T1 e T2 differiscono al più di 1. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 4 Alberi 1-bilanciati col minimo numero di nodi. Allora il num. di nodi nh di un albero 1-bilanciato di altezza h di dimensione minima soddisfa alle equazioni di ricorrenza: n0 = 1 n1 = 2 nh = nh-1 + nh-2 + 1 per k ≥ 2 Risolvendo per un minorante: n2 = n0 + n1 + 1 > n0 + n0 = 2n0 = 2 n4 = n2 + n3 + 1 > n2 + n2 = 2n2 > 2⋅2 = 22 n6 = n4 + n5 + 1 > n4 + n4 = 2n4 > 2⋅22 = 23 ... n2i > 2i, d'altra parte si ha n2i+1 > 2i, quindi nh > 2⎣h/2⎦ Dunque n = Ω((√2)h) e anche log nh > ⎣h/2⎦ > h/2 – 1 h = O(log n), quindi h = Θ(log n) 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 6 1 Gli alberi 1-bilanciati sono bilanciati. Alberi di Fibonacci (= alberi 1-bilanciati di dimensione minima) Dunque il numero di nodi minimo di un albero 1-bilanciato cresce esponenzialmente rispetto all'altezza dell'albero; quindi anche il num. di nodi di un albero 1-bilanciato qualsiasi cresce esponenzialmente rispetto all'altezza, e l'altezza è quindi logaritmica nel numero dei nodi. Per gli alberi 1-bilanciati (in altezza): h = Θ(log n) Con ragionamento analogo si vede che ciò vale più in generale per gli alberi k-bilanciati, con k fissato. h=0 h=1 h=2 h=3 Gli alberi 1-bilanciati o k-bilanciati sono dunque bilanciati ! h=4 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 7 21/01/10 21.23 Alberi AVL (dai nomi dei due inventori) AV vive attualmente in Israele, L è morto a Mosca nel 1997. alberi AVL: alberi di ricerca binari che vengono mantenuti 1-bilanciati. Come ? E. Giovannetti - AlgELab-09-10 - Lez.35 9 Автобиография (Autobiografia) Первая научная работа была сделана мной в 1944 г., когда я был студентом 4-го курса. ... Раньше, чем на Западе, мы разработали метод организации программ, которые могут использовать себя, как подпрограмму и как подпрограммы своих подпрограмм. Вместо системы списков, использующей й язык LISP, LISP мы разработали б удобные б стандарты программирования списков (это же сделал Д. Кнут, но после нас). Наконец, следует отметить конструкцию текущей справочной, разработанную E.M. Ландисом и мною, для которой количество элементарных действий, как для включения нового элемента информации, так и для исключения старого пропорционально логарифму объема справочной. ... 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 E. Giovannetti - AlgELab-09-10 - Lez.35 10 Alberi AVL E. M. Landis Evgenii Mikhailovich Landis was born on October 6, 1921, in Kharkov. Four years later, the family moved to Moscow. His interest to mathematics arose early, when he was in high school; so it was natural to him to apply to The Department of Mathematics and Mechanics of the Moscow State University. He was admitted there in 1939, but he was not able to study for long time: he was drafted, and in the six years that followed he had to fight in two wars; he was wounded, he was shell-shocked, he got severe frost-bites, many times he was on the edge. In 1945, when the war was over, Evgenii Mikhailovich was discharged, and he re-enrolled in the MSU. ... By the time he graduated from the Moscow State University, he had had 5 published papers. However, because of the official antisemitic policies that were in place at that time, he was denied the admission to the graduate school. He started working as a school teacher. Finally, Landis got his PhD in 1953, and, in 1956, he wrote his Doctor of Science di dissertation i "Some "S properties i off the h solutions l i off Elliptic Elli i Equations." E i " This Thi dissertation di i was a starting point for his interest in qualitative theory of PDEs. It is impossible to survey all his work in his direction. ... However, he worked in other fields as well. In 1962, in collaboration with Adel'son-Velsky, he published a paper "An algorithm for the organization of information." According to their algorithm, for a data structure that contains entries, the number of operation that is required for adding a new entry, and the number of operation that is required for retrieving an entry are proportional to log. This algorithm is called the AVL algorithm; now it is a part of any course in computer science, and it is used in many software products. ... He loved music; one could often see him in the Moscow Conservatory. He liked to draw, his paintings were part of an exhibition in the MSU Faculty Club. He lived in a difficult place in a difficult time and was making the life around him better. 21/01/10 21.23 8 G. M. Adelson-Velskii Inventati nel 1962 dai due (non tre !) matematici sovietici Adelson-Velskii (Адельсон-Вельский) e Landis (Ландис) 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 11 Le operazioni di inserimento ed eliminazione di un elemento effettuano ogni volta, se necessario, un ribilanciamento, per mezzo di opportune trasformazioni dell'albero, dette (un po' fantasiosamente) rotazioni, che lo rendono bilanciato pur mantenendone la proprietà di essere un albero di ricerca. Esempio: ribilancia con una "rotazione" " t i " inserisci 3 7 7 5 5 5 3 7 3 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 12 2 Alberi AVL Definizioni Un altro esempio: • sbilanciamento di un nodo (o di un albero) = differenza fra le altezze del sottoalbero di sinistra e di quello di destra; albero T Æ ribilancia con una "rotazione" " t i " inserisci 6 7 5 7 5 hS 6 5 D S 7 E. Giovannetti - AlgELab-09-10 - Lez.35 hD •sbil > 0: l'albero "pende" a sinistra; •sbil = 0: il nodo è "perfettamente bilanciato"; •sbil < 0: l'albero "pende" a destra; 6 21/01/10 21.23 sbil(v) = sbil(T) = hS - hD v 13 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Sbilanciamento e alberi 1-bilanciati. 14 Nota terminologica. Nota: è indifferente considerare lo sbilanciamento come • proprietà di un albero, oppure • proprietà del nodo radice di quell'albero. Nota Bene: sbil(T) = 0 non implica che T sia 1-bilanciato; o, considerando lo sbilanciamento come proprietà dei nodi: sbil(v) = 0 non implica che ll'albero albero di radice v sia 1-bilanciato 1 bilanciato • Considerando lo sbilanciamento come proprietà dei nodi, se un nodo ha sbilanciamento < 2 in valore assoluto, si dice talvolta per brevità che il nodo è 1-bilanciato. • Analogamente un nodo il cui sbilanciamento sia > 2 in valore assoluto viene talvolta detto per brevità nodo sbilanciato. • Un albero binario 1-bilanciato è q quindi un albero binario in cui tutti i nodi sono 1-bilanciati. Un albero T è 1-bilanciato (in altezza) se e solo se per ogni sottoalbero T' di T si ha |sbil(T')| ≤ 1 (dove fra i sottoalberi di un albero T vi è anche T stesso), o, considerando lo sbil. come proprietà dei nodi: in ogni nodo v di T si ha |sbil(v)| ≤ 1. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 15 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Ribilanciamento. Sbilanciamento a sinistra. Se T è un albero binario di ricerca 1-bilanciato, l'inserimento o l'eliminazione di un nodo può causare in qualche nodo di T uno sbilanciamento di al massimo ± 2. Sia T un albero binario di ricerca di radice b con sbil(b) = +2, e con |sbil(u)| ≤ 1 per ogni altro nodo u. cioè per tutti gli altri nodi v dell'albero sia |sbil(v)| ≤ 1. • Nota: T è un albero 2-bilanciato i cui sottoalberi propri sono tutti 1-bilanciati. • Come si trasforma un tale albero binario di ricerca T in un albero binario di ricerca 1-bilanciato ? E. Giovannetti - AlgELab-09-10 - Lez.35 17 sbil(b) = +2 b • Consideriamo allora un albero binario di ricerca T in cui: • sbilanciamento della radice = ± 2; • i sottoalberi sinistro e destro siano 11-bilanciati, bilanciati, e quindi tutti i sottoalberi siano 1-bilanciati, 21/01/10 21.23 16 h+2 S D h 2 • L'albero D può anche essere vuoto (se D è vuoto (h = -1), allora S ha due livelli, cioè altezza 1), ma • l'albero S sicuramente non lo è, quindi ha un nodo radice a e due figli SS e SD. T ha quindi una delle forme seguenti: 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 18 3 Sbilanciamento a sinistra: i due casi. caso SS (sottocasi 1 e 2) b h D 1 1 2 b SS D 1 SD h h+2 h D SD 2 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 h+2 19 21/01/10 21.23 b sbil = +2 a h D SD 1 1 h+2 21/01/10 21.23 21 21/01/10 21.23 Caso SS (sottocaso 1): rotazione SS. 2 E. Giovannetti - AlgELab-09-10 - Lez.35 22 Caso SS (sottocaso 1): rotazione SS. sbil = 0 a sbil = 0 b b h+1 D h h+1 h+1 SS 1 SD D h h+1 1 SS a (SD b D) Abbiamo applicato una specie di proprietà associativa; • SS ha diminuito di 1 l'annidamento, quindi è salito di 1 liv.; • D ha aumentato di 1 l'annidamento, quindi è sceso di 1 liv.; • SD ha lo stesso annidamento, quindi lo stesso livello. 21/01/10 21.23 1 1 SS a (SD b D) E. Giovannetti - AlgELab-09-10 - Lez.35 SD h D SD SS 2 (SS a SD) b D SS 20 Caso SS (sottocaso 1): animazione rotazione SS. a a 2 E. Giovannetti - AlgELab-09-10 - Lez.35 b sbil = +2 SS 1 1 Sfruttiamo la rappresentazione lineare infissa dell'albero: (SS a SD) b D (omettendo le parentesi più esterne) • bisogna trasformarlo in modo da far salire SS e scendere D mantenendo la stessa sequenza inorder; • a tal fine basta parentesizzare diversamente, giacché il livello (della radice) di un sottoalbero in un albero è dato dal numero di parentesi in cui è annidato. Caso SS (sottocaso 1): animazione rotazione SS. h+2 h D SD SS 2 Nota: nei disegni il nome del caso coincide con il nome del sottoalbero che "causa" lo sbilanciamento. a SS h+2 Nota Bene: SD e D possono anche essere vuoti; SS è sicuramente non vuoto. a a SD SS b b a h+2 Caso SS (sottocaso 1) caso SD E. Giovannetti - AlgELab-09-10 - Lez.35 23 SS a (SD b D) Abbiamo applicato una specie di proprietà associativa; • SS ha diminuito di 1 l'annidamento, quindi è salito di 1 liv.; • D ha aumentato di 1 l'annidamento, quindi è sceso di 1 liv.; • SD ha lo stesso annidamento, quindi livello, di prima. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 24 4 Riassumendo: rotazione SS (nel sottocaso 1). b sbil = +2 Caso SS (sottocaso 2) sbil = 0 a a b sbil = +2 a b h+2 SS h D SD 1 1 SS 2 SD D h+1 h E. Giovannetti - AlgELab-09-10 - Lez.35 h D SS 25 b h+2 1 (SS a SD) b D SS a (SD b D) Come si vede, • lo sbilanciamento della radice passa da 2 a 0; • l'altezza dell'albero diminuisce di 1 (passa da h+3 ad h+2); • lo sbilanciamento del sottoalbero destro (SD b D) è 0. 21/01/10 21.23 SD 2 21/01/10 21.23 D X SD h h+2 2 • Lo sbilanciamento del caso SS2 si può creare solo in seguito all'eliminazione di un nodo che faccia diminuire l'altezza di D da h+1 ad h, ma non in seguito a un inserimento. • Infatti l'inserimento di un nodo in un albero 1-bilanciato di radice b non può far aumentare l'altezza di entrambi i sottoalberi SS e SD (e se uno dei due avesse già altezza h+2 lo sbilanciamento si sarebbe già realizzato prima). E. Giovannetti - AlgELab-09-10 - Lez.35 27 Caso SD: verso la soluzione 1 D SD D 1 SD 2 21/01/10 21.23 SD 2 D h+2 h 1 E. Giovannetti - AlgELab-09-10 - Lez.35 h+2 2 E. Giovannetti - AlgELab-09-10 - Lez.35 SS (SS a SD) c D SS a (SD c D) La rotazione usata nel caso SS non è una soluzione ! Essa infatti fa scendere D eliminando così il dislivello di 2 fra SD e D, ma contemporaneamente fa salire SS creando così un nuovo dislivello di 2 fra SS e SD ! Il risultato è che il nodo radice a è ancora sbilanciato ! h 28 29 c b SS 1 • Evidentemente bisogna riuscire a "sollevare" SD senza far salire SS, ricordando che SD deve stare inorder fra a e c. Osserviamo che: • SS e D possono anche essere nulli, ma SD sicuramente non lo è. L'albero SD contiene quindi almeno un nodo radice non nullo, con due sottoalberi eventualmente nulli. 21/01/10 21.23 SS c h Caso SD sottocaso 1: T1 e T2 hanno altezze diverse. a SS sbil = -1 a Nota: nel disegno T2 può anche essere vuoto. a c h 1 26 a h+2 h+2 h Caso SD a h+2 SD c h+1 D E. Giovannetti - AlgELab-09-10 - Lez.35 b sbil = +2 21/01/10 21.23 SS (SS a SD) b D SS a (SD b D) Anche in questo caso la rotazione SS risolve il problema: • lo sbilanciamento della radice passa da 2 a -1; • l'altezza dell'albero rimane invariata; • lo sbilanciamento del sottoalbero destro (SD b D) è 1. Osservazione importante SS sbil = -1 a h T2 T1 h 1 D h 2 (SS a (T1 b T2)) c D Risistemiamo le parentesi mantenendo la sequenza inorder, in modo da diminuire l'annidamento sia di T1 che di T2, ma non quello di SS. Nota: Il sottocaso in cui i ruoli di T1 e T2 sono invertiti si tratta quindi con la stessa trasformazione. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 30 5 Caso SD (sottocaso 1): rotazione SD. Caso SD (sottocaso 1): rotazione SD. c b a a b h+2 h SS 1 h D T2 T1 h 1 h+1 SS 2 Nota: Il sottocaso in cui i ruoli di T1 e T2 sono invertiti si tratta quindi con la stessa trasformazione. E. Giovannetti - AlgELab-09-10 - Lez.35 c 31 21/01/10 21.23 h+2 SS h T1 1 h h+1 E. Giovannetti - AlgELab-09-10 - Lez.35 32 Caso SD (sottocaso 2). D b a a b SS 2 T2 D 1 c Nota: T1 e T2 possono essere entrambi vuoti (nel qual caso SS e D sono anch'essi vuoti). a h T1 h (SS a T1) b (T2 c D) • I sottoalberi T1 e T2 sono stati sollevati, D si è abbassato, SS è rimasto allo stesso livello. L'albero è 1-bilanciato. • L'altezza dell'albero è diminuita di 1, da h+3 ad h+2. • Nota: Si vede facilmente che la trasformazione funziona anche se le altezze di T1 e T2 sono scambiate. Caso SD (sottocaso 2). b T2 1 (SS a T1) b (T2 c D) Risistemiamo le parentesi mantenendo la sequenza inorder, in modo da diminuire l'annidamento sia di T1 che di T2, ma non quello di SS. 21/01/10 21.23 h c 1 h T1 h h T2 D SS 2 h c T1 T2 1 D h 1 A h iin questo Anche t caso la l rotazione t i SD risolve i l in i problema. bl Nota: A differenza del sottocaso 2 del caso SS, nel sottocaso 2 del caso SD l'altezza dell'albero diminuisce di 1 come nei casi SS, DD, e SD 1. b a h+1 h SS c T1 T2 D h h+1 1 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 33 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Osservazione. Sbilanciamento a destra. c u a h+2 b SS 1 h T1 h h T2 2 D h X • Lo sbilanciamento del caso SD2 si può creare sia in seguito all'eliminazione di un nodo che faccia diminuire l'altezza di D da h ad h-1, che in seguito a un inserimento di b con T1 e T2 entrambi vuoti. c c a inserisci b a b 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 34 35 sbil(u) = -2 h+2 S 2 D • È ovviamente speculare di quello a sinistra, quindi si scinde in due casi DD e DS che si risolvono con rotazioni anch'esse speculari rispettivamente di SS e DS. • Ad esempio, la rotazione DD sarà: S a (DS b DD) Æ (S a DS) b DD 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 36 6 Osservazione Le rotazioni "miste" come rotazioni doppie. Le rotazioni SD e DS possono essere ottenute per mezzo delle altre due. Esempio: rotazione SD (SS a (T1 c T2)) b D (SS a T1) c (T2 b D) Le rotazioni SS e DD sono l'una l'inversa dell'altra: (T1 a T2) b T3 21/01/10 21.23 SS Æ Å DD T1 a (T2 b T3) E. Giovannetti - AlgELab-09-10 - Lez.35 37 Le rotazioni "miste" come rotazioni doppie. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 38 Le rotazioni "miste" come rotazioni doppie. Le rotazioni SD e DS possono essere ottenute per mezzo delle altre due. Esempio: Le rotazioni SD e DS possono essere ottenute per mezzo delle altre due. Esempio: (SS a (T1 c T2)) b D (SS a (T1 c T2)) b D rotazione DD sul sinistro (SS a T1) c (T2 b D) rotazione DD sul sinistro ((SS a T1) c T2) b D SSaT1 c (T2 b D) (SSaT1 c T2) b D rotazione SS consideriamo (SS a T1) come un unico sottoalbero SSaT1 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 39 Le rotazioni "miste" come rotazioni doppie. rotazione DD sul sinistro SSaT1 c (T2 b D) (SSaT1 c T2) b D rotazione SS E. Giovannetti - AlgELab-09-10 - Lez.35 40 Le rotazioni SD e DS possono essere ottenute per mezzo delle altre due. Esempio: rotazione SD (SS a (T1 c T2)) b D (SS a T1) c (T2 b D) rotazione DD sul sinistro consideriamo (SS a T1) come un unico sottoalbero SSaT1 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Le rotazioni "miste" come rotazioni doppie. Le rotazioni SD e DS possono essere ottenute per mezzo delle altre due. Esempio: (SS a (T1 c T2)) b D 21/01/10 21.23 41 ((SS a T1) c T2) b D rotazione SS Per modificare un sottoalbero t tramite la rotazione SD basta quindi eseguire il seguente banale algoritmo: void sd(Node T) { dd(T.left); ss(T) } 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 42 7 Terminologia Riassumendo: • Le rotazioni SS e DD vengono dette rotazioni semplici. • Le rotazioni SD e DS vengono dette rotazioni doppie, proprio perché ognuna di esse si può ottenere per mezzo di due rotazioni semplici. • Per numero di rotazioni eseguite da un'operazione sugli alberi AVL si intende il numero di ribilanciamenti eseguiti: quindi una rotazione doppia conta per una. • La radice del (sotto-)albero cui si applica una rotazione viene talvolta impropriamente detto perno della rotazione. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 43 Anticipazione di conseguenza importante E. Giovannetti - AlgELab-09-10 - Lez.35 45 Inserimento: algoritmo ricorsivo astratto. void inser(Elemento el, AVLTree t) { if(t è vuoto) modifica t creando un nodo-radice contenente el; else if(chiaveDi(el) == chiaveDi(t.element)) sostituisci t.element con el; else { if(chiaveDi(el) < chiaveDi(t.element)) inser(el, t.sinist); else inser(el, t.destr); if(|sbil(t)| > 1) ribilancia t con l'opportuna rotazione; } } Domanda: il ribilanciamento di un sottoalbero può richiedere il successivo ribilanciamento di un altro (sotto-)albero ? La risposta nelle prossime slides. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 • Le rotazioni nei sottocasi SS2 e DD2 sono le uniche che lasciano invariata l'altezza del sottoalbero. • Ma l'inserimento di un nuovo elemento non può produrre i sottocasi di sbilanciamento SS2 e DD2. • Quindi una rotazione dovuta a inserimento decrementa sempre di 1 l'altezza dell'albero "ruotato". 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 44 Le operazioni di inserimento e cancellazione. • Come vedremo, un inserimento che sbilanci un albero ne aumenta sempre di 1 l’altezza. • Ma, come abbiamo appena visto, la susseguente rotazione dovuta a inserimento decrementa sempre di 1 l'altezza dell'albero "ruotato". • Alla fine, dopo l’inserimento e la rotazione, l’albero ha quindi la stessa altezza di prima dell’inserimento. dell inserimento. 21/01/10 21.23 • Le rotazioni nei casi SD, DS e nei sottocasi SS1, DD1 fanno diminuire di 1 l'altezza del sottoalbero cui sono applicate. 47 Per inserire o cancellare un elemento in un albero AVL: • si inserisce o si elimina l'elemento come in un albero binario di ricerca ordinario, creando o eliminando un nodo; • se in seguito a ciò qualche sottoalbero è diventato non più 1-bilanciato, lo si ribilancia tramite l'opportuna rotazione; • poiché le rotazioni funzionano sulla base dell'ipotesi che i due sottoalberi figli del nodo perno siano 1-bilanciati (e che quindi tutti i loro nodi abbiano sbil < 2 in valore assoluto), l'albero che bisogna ribilanciare è il più piccolo albero che si è sbilanciato: ciò è automaticamente garantito dalla definizione ricorsiva dell'algoritmo. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 46 Inserimento con sbilanciamento/ribilanciamento: una proprietà importante. • L'incremento di altezza di un sottoalbero T può portare lo sbilanciamento del genitore p di T da 1 a 2 o da –1 a –2. • Se ciò accade, anche l'altezza dell'albero di radice p aumenta sicuramente di 1. • Lo sbilanciamento provocato da un inserimento può essere solo l del d l genere SS1, SS1 DD1, DD1 SD SD, o DS. DS • Ma in tal caso la rotazione di ribilanciamento fa diminuire di 1 l'altezza dell'albero di radice p (vedi slide prec.). • Quindi, dopo il ribilanciamento, l'albero di radice p ha la stessa altezza di prima dell'inserimento (l'inserimento sbilanciante l'ha fatta aumentare di 1, la rotazione l'ha fatta diminuire di 1). 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 48 8 Inserimento con sbilanciamento/ribilanciamento. Vale dunque il seguente importante Lemma. L'inserimento di un nodo in un (sotto-)albero T, se provoca una rotazione avente per perno la radice di T, non modifica l'altezza di T rispetto a prima dell'inserimento. Conseguenza: L'inserimento di un nodo in un (sotto-)albero T, se provoca lo sbilanciamento di T ma di nessun suo sottoalbero, sottoalbero e quindi una rotazione di T, non ne modifica l'altezza; dunque non può causare lo sbilanciamento di nessun altro (sotto-)albero che contenga T. Quindi: Teorema: Un inserimento in albero AVL richiede al massimo una rotazione (semplice o doppia). 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 49 Esempio (caso SS) albero T Æ SS h 51 Altezza e operazioni sull'albero 1 E. Giovannetti - AlgELab-09-10 - Lez.35 D 2 b h+2 SS 1 SD h D • inizialmente l'altezza di SS, SD, D è h, l'altezza di T è h+2; • si inserisce un nodo in SS: •l'altezza di SS diventa h+1, l'altezza di T diventa h+3; •ma T si sbilancia; •allora si fa una rotazione SS per ribilanciare; ma essa fa di nuovo diminuire di 1 l'altezza di T, riportandola ad h+2. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 50 typedef struct Nodo* AVLTree; (nel file .h) typedef struct Nodo { Studente elem; AVLTree sx; AVLTree dx; int h; // altezza } Nodo; (nel file .c) int altezza(AVLTree t) { se t non è vuoto restituisce il valore del campo h, se t è vuoto restituisce –1 (oppure 0, a seconda di come si decide di contare le altezze) } int sbil(AVLTree t) { ... } 21/01/10 21.23 // sbilanciamento E. Giovannetti - AlgELab-09-10 - Lez.35 52 Altezza e operazioni: una proprietà ovvia. • L'inserimento o cancellazione di un nodo in un albero può modificarne l'altezza; • a sua volta la variazione di altezza di un sottoalbero-figlio può modificare l'altezza del nodo genitore (l'altezza di un albero è uguale a 1 + l'altezza del più alto dei suoi due figli); • pertanto in ciascun (sotto-)albero T, dopo l'inserimento o cancellazione in uno dei sottoalberi-figli, sottoalberi figli, bisogna bisogna: • controllare se l'altezza di tale figlio è variata; • se è variata: • controllare se tale variazione provoca una variazione dell'altezza dell'albero T, e se si, aggiornare il campoaltezza (del nodo radice di T); • controllare se ciò ha prodotto uno sbilanciamento. 21/01/10 21.23 SD h Esempio in C (italo-inglese) • Affinché il tempo necessario per l'inserimento si mantenga proporzionale alla lunghezza del cammino dalla radice dell'albero fino al punto di inserimento – e quindi O(log n) – bisogna che: • sbil(T) possa essere (ri-)calcolato in tempo costante, senza visitare tutto il sottoalbero T. • Ma Nota Bene: • lo sbil. di un nodo non è funzione degli sbil. dei figli; • l'altezza è invece funzione delle altezze dei figli. • Ogni nodo deve quindi contenere il valore dell'altezza del sottoalbero di cui quel nodo è radice: la struttura-nodo deve quindi contenere un campo supplementare altezza. • Naturalmente ogni operazione di modifica dell'albero deve aggiornare correttamente tale campo. E. Giovannetti - AlgELab-09-10 - Lez.35 a a Struttura-dati per la realizzazione. 21/01/10 21.23 b 53 • L'inserimento o cancellazione di un nodo può causare una variazione del valore del campo-altezza solo nei nodi posti sul cammino dalla radice al nodo creato. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 54 9 Inserimento: algoritmo ricorsivo. Qualche suggerimento per l'implementazione void inser(Elemento el, AVLTree t) { if(t è vuoto) modifica t creando un nodo-radice contenente el, con altezza = 0 ; else if(chiaveDi(el) == chiaveDi(t.element)) sostituisci t.element con el; else { if(chiaveDi(el) f( h D ( l) < chiaveDi(t.element)) h D( l )) inser(el, t.sinist); else inser(el, t.destr); } } if(|altezza(t.sinist) – altezza(t.destr)| < 2) t.altezza = 1 + max(altezza(t.sinist), altezza(t.destr)); else individua la rotazione opportuna ed eseguila; Nota: Le procedure di rotazione devono, al loro interno, aggiornare correttamente i campi-altezza dei nodi coinvolti. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 55 Conviene strutturare il codice con procedure ausiliarie, es.: void aggiornaAltezza(Tree t) { ... se t non è vuoto ecc. } void ribilanciaOppureAggiornaAltezza(Tree* pt) { assumendo che nei nodi dei sottoalberi-figli le altezze siano tutte corrette,, calcola lo sbilanciamento di *pt p e, se necessario, effettua l'opportuna rotazione; altrimenti aggiorna semplicemente l'altezza di *pt. } void ss( ... ) { ... } eccetera. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 56 Correttezza dell'algoritmo ricorsivo di inserimento Correttezza dell'algoritmo ricorsivo di inserimento Dimostrazione (facile) di correttezza per induzione strutturale sull'albero. • Passo: Inserimento in un albero T non vuoto, di radice r. Ip. Ind.: L'inserimento in T.sinist o T.destr è corretto. Tesi Ind.: L'inserimento in T è corretto. Dimostrazione del passo. Dopo l'inserimento in T.sinist o T.destr: • per ip. ind. i campi altezza dei (nodi-radice di) T.sinist e T.destr contengono g i valori corretti;; lo sbil. della radice r di T si ottiene quindi con una semplice differenza; • per ip. ind. i due sottoalberi T.sinist o T.destr sono ancora 1-bilanciati, cioè tutti i nodi di T, tranne al più la radice r, hanno |sbil| < 2; • allora se |sbil| di r risulta > 1, T è un albero in cui solo la radice è sbilanciata: che è proprio la situazione che può essere risolta da un'opportuna rotazione; • altrimenti T è già 1-bilanciato, basta aggiornare il campo altezza della radice. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 58 • Base: L'inserimento di un elemento nell'albero vuoto è corretto p perché crea un albero costituto da un solo nodo, quindi 1-bilanciato, con il campo-altezza correttamente impostato a 0. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 57 Correttezza dell'algoritmo ricorsivo di inserimento • Allora le tre ultime righe della descrizione dell'algoritmo, le quali appunto: • aggiornano il campo-altezza della radice, oppure • effettuano una rotazione con perno la radice (che ne imposta p anche correttamente l'altezza)) realizzano un inserimento corretto, perché: • l'albero T modificato è ancora di ricerca e 1-bilanciato; • i campi-altezza contengono i valori corretti. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 59 Inserimento: esempio. • Si inserisce l'elemento creando un nuovo nodo al posto di un nodo nullo. L'altezza del sottoalbero che prima era nullo passa quindi da –1 a 0. Indicando con h(v) l'altezza inserisci 6: 10 dell'albero di radice v, si ha: h(sx di 7), cioè h(6) : -1 Æ 0; h(7): 0 Æ 1 4 15 h(4): 1 Æ 2; h(10): 3 Æ 3 Sbilanciamento dei nodi: 3 12 7 18 sbil(7): 0 Æ 1; sbil(4): 0 Æ -1; sbil(10): -1 Æ 0. 6 19 L'albero è rimasto 1-bilanciato, non occorre ribilanciare, ma solo aggiornare E.i Giovannetti campi-altezza. - AlgELab-09-10 - Lez.35 60 21/01/10 21.23 10 Inserimento: un altro esempio. Continuazione esempio. inserisci 6: 10 4 15 3 7 6 Variazioni delle altezze: h(6): -1 Æ 0; h(7): 0 Æ 1 h(4): ( ) 1 Æ 2;; h(10): 2 Æ 3 ... Variazioni degli sbil.: ... sbil(10): 1 Æ 2 • Si crea uno sbilanciamento, occorre una rotazione SD di perno il nodo 10. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 61 10 4 15 3 7 6 ((•3•) 4 ((•6•) 7 •)) 10 (•15•) ( SS 4 ( T1 7 T2)) 10 D 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Continuazione esempio. rotazione SD Continuazione esempio 10 4 rotazione SD 7 4 15 3 3 7 10 6 15 6 ((•3•) 4 (•6•)) 7 (• 10 (•15•)) ( SS 4 T1 ) 7 (T2 10 D ) 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 63 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 64 Inserimento: algoritmo iterativo. • Si effettua l'inserimento eseguendo l'algoritmo iterativo per alberi di ricerca ordinari (vedi slides lez 29, n.36). • Poi si risale nel cammino percorso dalla radice al nodo, aggiornando i valori dei campi-altezza, e ricalcolandone gli sbilanciamenti. • Se si incontra un nodo il cui sbilanciamento diventa +2 2 o –2 2, si effettua l'opportuna rotazione e si termina (infatti il Teorema di slide 49 garantisce che non occorre fare altro). • Anche se si incontra un nodo in cui l'aggiornamento non cambia l'altezza, si può ovviamente terminare. Nota: Nell’algoritmo iterativo è conveniente usare nodi con riferimento al genitore ! E. Giovannetti - AlgELab-09-10 - Lez.35 L'altezza dell'albero di radice 7 è la stessa di prima dell'inserimento. Quindi il genitore e gli antenati del perno non vengono sbilanciati. ((•3•) 4 (•6•)) 7 (• 10 (•15•)) Inserimento: algoritmo iterativo. 21/01/10 21.23 62 65 void inser(Elemento el, AVLTree t) { while(t non è vuoto) { if(chiaveDi(el) < chiaveDi(t.element)) t = t.sinist; else if(chiaveDi(el) > chiaveDi(t.element)) t = t.destr; else { sostituisci t.element con el; return; } } modifica t creando un nodo contenente el con altezza = 0; p = genitore di t; while(p non è nullo) { if(sbil(p) uguale a -2 o +2) { esegui l'opportuna rotazione; return; } else { aggiorna l'altezza di p; if(l'altezza di p non è cambiata) return; } p = genitore di p; } } 21/01/10 21.23 Ma attenzione: vedi slide successiva ! E. Giovannetti - AlgELab-09-10 - Lez.35 66 11 Inserimento: algoritmo iterativo. Eliminazione del minimo e cancellazione di elemento Attenzione ! Come nel caso degli alberi di ricerca ordinari l'algoritmo descritto nella slide precedente è direttamente traducibile in una procedura C, ma non in un metodo Java o C#. Per l'implementazione in Java occorre adottare una versione analoga a quella ad es. di slide lez29 n.70. • L'eliminazione ordinaria di un nodo in un albero può causare una diminuzione ma non un aumento dell'altezza dell'albero. • Il decremento di altezza di un sottoalbero T può portare lo sbilanciamento del genitore p di T da 1 a 2 o da –1 a –2. • Se ciò accade, l'altezza dell'albero di radice p sicuramente rimane invariata (perché si "accorcia" il sottoalbero-figlio che è già meno alto). • In tal t l caso c s la l successiva succ ssiv rotazione r t zi n di ribilanciamento ribil nci m nt può far diminuire di 1 l'altezza dell'albero di radice p (nei casi SD, DS, SS1, DD1). Quindi: • Dopo il ribilanciamento, l'altezza dell'albero di radice p può risultare decrementata di 1 rispetto all'altezza di prima della cancellazione del nodo. • Ciò può provocare uno sbilanciamento in un nodo antenato, quindi una rotazione che può diminuire l'altezza, e così via. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 67 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Eliminazione del minimo e cancellazione di elemento 68 Esempio • Nel caso peggiore si possono quindi avere sbilanciamenti a cascata, uno per ogni nodo del cammino dalla radice al nodo eliminato. • Nel caso peggiore si hanno quindi Θ(log n) rotazioni; la complessità dell'operazione è dunque ancora O(log n). • Le versioni ricorsiva e iterativa dell'algoritmo astratto sono, in base alle osservazioni precedenti, abbastanza ovvie, e vengono lasciate per esercizio. Cancelliamo il nodo 1: • il sottoalbero di radice 2 diminuisce di uno l'altezza (ma non si sbilancia); • per effetto di ciò il sottoalbero di radice 3 non varia la propria altezza ma il suo sbilanciamento diventa -2. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 69 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 Esempio 70 Esempio (continua). • Si esegue una rotazione DD: l'altezza del sottoalbero ruotato diminuisce di 1. 8 13 5 3 2 11 6 4 7 (•2•) 3 ( (•4•) 5 (• 6 (•7•)) ) E. Giovannetti - AlgELab-09-10 - Lez.35 12 10 ((•2•) 3 (•4•)) 5 (• 6 (•7•)) 21/01/10 21.23 9 16 ((•2•) 3 (•4•)) 5 (• 6 (•7•)) 71 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 19 14 15 17 20 18 72 12 Esempio (continua). Esempio (continua). Lo sbilanciamento del nodo 8 diventa –2. 8 h = 5 13 13 5 3 2 7 nuova rotazione DD, con perno 8 9 16 12 19 T1 8 (T2 13 T3) 15 16 5 14 10 h = 4 8 11 6 4 21/01/10 21.23 • L'altezza del sottoalbero ruotato è diminuita di 1. 17 3 20 2 6 4 9 7 19 14 12 15 10 17 20 18 (T1 8 T2) 13 T3 18 E. Giovannetti - AlgELab-09-10 - Lez.35 11 73 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 74 Esempio di cancellazione: rotazioni a cascata. Esempio (continua). • Se l'albero di radice 13 è a sua volta l'albero-figlio sinistro o destro di un altro albero, potrebbe sbilanciarlo, e così via. 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 75 Esempio di rotazioni a cascata (continua) 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 76 Esempio di rotazioni a cascata (continua) 77 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 78 13 Esempio di rotazioni a cascata (continua) 21/01/10 21.23 E. Giovannetti - AlgELab-09-10 - Lez.35 79 14