Bilanciamento Alberi Binari di Ricerca G.T. 0.. e 0.. Alberi AVL (Adel'son-Vel'skii-Landis) Alberi Binari di Ricerca
Albero Binario di Ricerca DEFINIZIONE: è un albero binario proprio ad ogni nodo interno è associato un Entry (key, elem) è definito l'ordinamento: k(left(v)) k(v) k(rigt(v)) OPERAZIONI: find(k) -> ritorna l entry con key = k findall(k) -> iterator di tutte le entry con key = k insert(k, x) -> inserisce l entry remove(e) -> rimuove l entry, e la ritorna COMPLESSITA e BILANCIAMENTO O((n)) log(n+) <= (n) <= (n )/ 3 AVL Tree 4
Albero AVL DEFINIZIONE albero binario di ricerca bilanciato NODO BILANCIATO altezza sotto-albero sinistro differisce da altezza sotto-albero destro di al più una unità ALBERO BILANCIATO tutti i nodi sono bilanciati OPERAZIONI come in albero binario di ricerca COMPLESSITA' O((n)) O(log(n)) 5 AVL Tree - esempio 44 4 albero binario di ricerca bilanciato 7 78 3 3 50 88 48 6 6 3
Altezza di un AVL L altezza di un AVL con n entry è O(log n) Determiniamo n() - numero minimo di nodi di un AVL di altezza Risulta: n( ) = e n( ) = Risulta, per 3 : n() n ( ) n( ) n( ) = + n( ) + n( ) 7 Altezza di un AVL Poicé è n( ) > n( ) da: n( ) = + n( ) + n( ) risulta : n( ) > n( ) n( ) > n( ) > 4 n( 4) > 8 n( 6) > i n( i) per ogni i, tale ce i 8 4
Altezza di un AVL 3 Scelto idi modo ce risulti i = o e cioè: i = sostituendo il valore di i nella i n( ) > n( i) risulta: n( ) > n + n() e passando al logaritmo, risulta: < log n( ) + ce implica < log n + e = O(log n) 9 Rotazioni in albero binario di ricerca 0 5
Rotazione di un albero binario Rotazione destra di x su y γ α α β α x β y γ β γ la relazione d ordine rimane invariata Rotazione di un albero binario di ricerca Rotazione destra di x su y γ α α β α x β y γ β γ 6
Ulteriori esercizi Rotazione di nodi void rigtrotate( Position<E> x ) { // RIGHT-ROTATE Position<E> y = parent(x); setleftcild( y, rigtcild(x) ); setparent( rigtcild(x), y ); if ( isroot(y) ) { setroot(x); setnullparent(x); else if ( onleft(y) ) { setleftcild( parent(y), x ); setparent( x, parent(y) ); else { setrigtcild(parent(y), x ); setparent( x, parent(y) ); setrigtcild(x,y); setparent(y,x); return; 3 Rotazione di un albero binario di ricerca Rotazione destra di x su y γ α α β Position<E> y = parent(x); β γ setleftcild( y, rigtcild(x) ); setparent( rigtcild(x), y ); 4 7
Rotazione di un albero binario di ricerca Rotazione destra di x su y γ α if α( isroot(y) β ) { setroot(x); setnullparent(x); β γ else if ( onleft(y) ) { setleftcild( parent(y), x ); setparent( x, parent(y) ); else { setrigtcild(parent(y), x ); setparent( x, parent(y) ); 5 Rotazione di un albero binario di ricerca Rotazione destra di x su y γ α α β β γ setrigtcild(x,y); setparent(y,x); 6 8
Insert in AVL-tree Come per albero binario di ricerca + eventuale ripristino del bilanciamento mediante opportune rotazioni 7 AVL Tree - Insert 44 4 come per albero binario di ricerca 7 78 3 3 50 88 48 6 insert 54 8 9
AVL Tree - Insert 44 5 ripristino bilanciamento 7 z 78 4 3 y 50 3 88 ) rotazione a sinistra di su x 48 6 54 T T 3 T 0 T 9 AVL Tree - Insert 44 5 ripristino bilanciamento z 7 78 4 3 y x 50 6 3 88 ) rotazione a destra di su Z 48 54 T T 3 T 0 T 0 0
AVL Tree - Insert 44 4 bilanciamento O.K. 7 x 6 3 3 50 y 78 z 48 54 T 88 T 0 T T 3 Insert in AVL - caso Z +3 + + + + Z A + B C A B C W
Insert in AVL - caso passo Z +3 Z +3 + + A + B - C D A + B C - D w 3 Insert in AVL - caso passo Z +3 + + + Z + A + B C - D A - B C D 4
AVL Tree ristrutturazione a 3 nodi c Z b () b a () c (Z) a δ γ α β γ δ α β ridenominazione nel inorder 5 AVL Tree ristrutturazione a 3 nodi c Z b () a a () c (Z) α b δ α β γ δ β γ ridenominazione nel inorder 6 3
Inserimento inserimento nodo W come in BST, ciò può sbilanciare qualce nodo nel percorso da nodo W a radice : nel cammino da W a radice Z primo nodo sbilanciato figlio di Z figlio di effettuare ristrutturazione su tre nodi (inorder ) il bilanciamento è ripristinato sia localmente sia globalmente complessità ribilanciamento: O() 7 Remove in AVL-tree Come per albero binario di ricerca + eventuale ripristino del bilanciamento mediante opportune rotazioni 8 4
AVL Tree - Remove 44 4 7 remove 3 6 3 3 50 78 48 54 88 9 AVL Tree - Remove 44 4 z rotazione a sinistra di su Z 7 remove 3 y 6 3 T 0 3 50 78 x 48 54 0 88 T T T 3 30 5
AVL Tree - Remove y 6 4 z 44 3 risultato finale x 78 7 50 0 88 T 0 48 T 54 T T 3 3 AVL Tree - Remove ) come per albero binario di ricerca, rimuovi nodo avente padre W ) nel cammino dal nodo W alla radice vi può essere un primo nodo sbilanciato, ciamiamolo Z 3) diciamo il figlio più alto di Z e il figlio più alto di ( se non è unico, si prende il nodo ce è dalla stessa parte di ) 4) effettuiamo la ristrutturazione sui tre nodi (,, Z), ciò può ridurre l'altezza dell'albero con radice in b di una unità 5) il bilanciamento viene ripristinato localmente ma non necessariamente a livello globale, un ascendente di b può divenire sbilanciato, ripetere l'operazione... complessità ribilanciamento: O(log n) 3 6
Fine 33 Code Fragment 0.7 G.T. p. 438 public class AVLTree<K,V> extends BinarySearcTree<K,V> implements Dictionary<K,V> { public AVLTree( Comparator<K> c ) { super(c); protected static class AVLNode<K,V> extends BTNode<Entry<K,V>> { protected int eigt; // we add a eigt field to a BTNode //........ //........ 34 7
Code Fragment 0.7 AVLNode protected static class AVLNode<K,V> extends BTNode<Entry<K,V>>{ protected int eigt; // we add a eigt field to a BTNode AVLNode(<Entry<K,V>> element, BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> rigt) { super(element, parent, left, rigt); eigt = 0; if ( left!= null ) eigt = Mat.max( eigt, + ((AVLNode<K,V>) left).getheigt()); if (rigt!= null) eigt = Mat.max(eigt, + ((AVLNode<K,V>) rigt).getheigt()); // we assume tat te parent will revise its eigt if needed public void setheigt(int ) { eigt = ; public int getheigt() { return eigt; 35 Code Fragment 0.7 AVLTree<K,V> 3 //Creates a new binary searc tree node (overrides super's ver.) protected BTPosition<Entry<K,V>> createnode (<Entry<K,V>> element, BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> rigt) { return new AVLNode<K,V>(element, parent, left, rigt); // Returns te eigt of a node (call back to an AVLNode) protected int eigt (Position<Entry<K,V>> p) { return ( (AVLNode<K,V> ) p ).getheigt(); 36 8
Code Fragment 0.7 4 //Sets te eigt of an internal node (call back to an AVLNode) // called only if p is internal protected void setheigt( Position<Entry<K,V>> p ) { ( (AVLNode<K,V> ) p ).setheigt( + Mat.max( eigt(left(p)), eigt(rigt(p)) ) ); //Returns weter a node as balance factor between - and protected boolean isbalanced(position<entry<k,v>> p) { int bf = eigt( left(p)) - eigt(rigt(p) ); return ( (- <= bf) && (bf <= ) ); 37 Code Fragment 0.8 protected Position<Entry<K,V>> tallercild (Position<Entry<K,V>> p) { if ( eigt(left(p)) > eigt(rigt(p))) return left(p); else if (eigt(left(p)) < eigt(rigt(p))) return rigt(p); // equal eigt cildren - break tie using parent's type if ( isroot(p) ) return left(p); if ( p == left(parent(p))) return left(p); else return rigt(p); 38 9
Code Fragment 0.8 protected void rebalance( Position<Entry<K,V>> zpos ) { if( isinternal(zpos) ) setheigt(zpos); wile (! isroot(zpos) ) { //traverse up te tree towards te root zpos = parent(zpos); setheigt(zpos); if (! isbalanced(zpos) ) { // perform a 3node restruct. at zpos's tallest grandcild Position<K,V>> xpos = tallercild( tallercild(zpos)); // tri-node restructure (from parent class) zpos = restructure(xpos); setheigt( left(zpos) ); //recompute eigts setheigt( rigt(zpos)); setheigt( zpos ); //end if // end wile //end metod 39 Code Fragment 0.8 3 public Entry<K,V> insert (K k, V v) trows InvalidKeyException { Entry<K,V> toreturn = super.insert(k, v); // calls our new createnode rebalance (actionpos); // rebalance up from te insertion position return toreturn; public Entry<K,V> remove (Entry<K,V> ent) trows InvalidEntryException { Entry<K,V> toreturn = super.remove(ent); if (toreturn!= null) // we actually removed someting rebalance (actionpos); // rebalance up te tree return toreturn; 40 0
BinarySearcTree - restructure. protected Position restructure(position<entry<k,v>> x ) { BTPosition<Entry<K,V>> a, b, c, t, t, t3, t4; Position<Entry<K,V>> y = parent(x); // assumes x as a parent Position<Entry<K,V>> z = parent(y); // assumes y as a parent boolean xleft = (x == left(y)); boolean yleft = (y == left(z)); Position<Entry<K,V>> xx = (Position<Entry<K,V>>)x, yy = (Position<Entry<K,V>>)y, zz = (Position<Entry<K,V>>)z; 4 BinarySearcTree - restructure. if ( xleft && yleft ) { a = xx; b = yy; c = zz; t = a.getleft(); t = a.getrigt(); t3 = b.getrigt(); t4 = c.getrigt(); else if (! xleft && yleft ) { a = yy; b = xx; c = zz; t = a.getleft(); t = b.getleft(); t3 = b.getrigt(); t4 = c.getrigt(); b a t a t c Z t c Z b t3 t4 t4 t t3 4
BinarySearcTree - restructure. else if ( xleft &&! yleft) { a = zz; b = xx; c = yy; t = a.getleft(); t = b.getleft(); t3 = b.getrigt(); t4 = c.getrigt(); else { // rigt-rigt a = zz; b = yy; c = xx; t = a.getleft(); t = b.getleft(); t3 = c.getleft(); t4 = c.getrigt(); 43 BinarySearcTree - restructure. // put b at z's place if ( isroot(z) ) { root = b; b.setparent(null); else { BTPosition<Entry<K,V>> zparent = (BTPosition<Entry<K,V>>) parent(z); if ( z == left(zparent) ) { b.setparent(zparent); zparent.setleft(b); else { // z was a rigt cild b.setparent(zparent); zparent.setrigt(b); 44
BinarySearcTree - restructure 3. // place te rest of te nodes and teir cildren b.setleft(a); a.setparent(b); b.setrigt(c); c.setparent(b); a.setleft(t); t.setparent(a); a.setrigt(t); t.setparent(a); c.setleft(t3); t3.setparent(c); c.setrigt(t4); t4.setparent(c); a b c // Reset te location-aware entries ((BSTEntry<K,V>) a.element()).pos = a; ((BSTEntry<K,V>) b.element()).pos = b; ((BSTEntry<K,V>) c.element()).pos = c; T T T3 T4 return b; // te new root of tis subtree 45 3