Alberi Binari di Ricerca Prof. G. M. Farinella gfarinella@dmi.unict.it www.dmi.unict.it/farinella
Riferimenti Bibliografici Cormen T.H., Leiserson C.E., Rivest R.L Introduction to Algorithms, Third Edition, MIT Press, 2009. Argomentitrattatiin questalezione: III Data Structures, 12 Binary Search Trees
Nella lezione precedente Insiemi dinamici che implementano le funzionalità di Item search(key key) void insert(key key, Item item) void delete(key key)
Nella lezione precedente Implementazione Array ordinato: ricerca O(log n) inserimento/cancellazione O(n) Lista non ordinata: Ricerca/cancellazione O(n) inserimento O(1)
Riepilogo Concetti di Base: Alberi Binari Prof. G. M. Farinella gfarinella@dmi.unict.it www.dmi.unict.it/farinella
Alberi Binari Un albero binario è un albero dove ogni nodo ha al massimo due figli. Tutti i nodi tranne la radice hanno un nodo padre. Le foglie dell albero non hanno figli.
Sottoalberi
Sottoalberi
i è padre di k e j j e k sono i due figli di i (i,j) è l arco che unisce i e j Padre - Figlio
Foglie, nodi interni e percorsi In nodo di un albero binario si dice nodo foglia se non ha figli (cioè se entrambi i sottoalberi di cui è radice sono vuoti). Un nodo si dice nodo interno se ha almeno un figlio. Un percorso dal nodo i al nodo j è la sequenza di archi che devono essere attraversati per raggiungere il nodo j dal nodo i.
In un albero binario la profondità di un nodo è la lunghezza del percorso dalla radice al nodo (cioè il numero di archi tra la radice e il nodo). La profondità maggiore di un nodo all interno di un alberoè l altezza dell albero. Profondità e altezza
Albero Binario Pieno Un albero binario si dice pieno se: tutte le foglie hanno la stessa profondità h tutti i nodi interni hanno grado 2 Un albero pieno di n nodi ha altezza esattamente Un albero pieno di altezza h ha esattamente 2*h+1-1 nodi (2*h-1 nodi interni + 2*h foglie).
Albero Binario Completo Un albero binario si dice completo se: tutte le foglie hanno profondità h o h-1, dove h è l altezza dell albero tutti i nodi interni hanno 2 figli, eccetto al più uno.
Rappresentazione alberi Binari Un albero binario si può rappresentare con una lista concatenata in cui si usano i campi: p[x] per puntare al padre del nodo x left[x] per puntare al figlio sinistro right[x] per puntare al figlio destro
Rappresentazione alberi Binari Se un figlio non esiste, il corrispondente puntatore è NIL. La radice, root[t], ha p[root[t]] = NIL. Se root[t] = NIL, l albero è vuoto Per le foglie lef t[x] = right[x] = NIL
Alberi Binari di Ricerca Prof. G. M. Farinella gfarinella@dmi.unict.it www.dmi.unict.it/farinella
Alberi Binari di Ricerca Un albero binario di ricerca è un albero binario con le seguenti caratteristiche: nei suoi nodi sono allocati gli elementi di un insieme T, su cui è definito un ordinamento totale Ovvero per tutti gli elelementi a, b, c di T valgono le seguenti: a a (riflessività) se a b e b a, allora a = b (antisimmetria) se a b e b c allora a c (transitività) a b oppureb a (totalità) se y è un nodo appartenente al sottoalbero sinistro di x, allora key[y] key[x] se y è un nodo appartenente al sottoalbero destro di x, allora key[y] key[x] Tutti gli elementi allocati nel sottoalbero sinistro di x precedono nell ordinamento l elemento allocato in x Tutti gli elementi allocati nel sottoalbero destro di x seguono nell ordinamento l elelemento allocato in x
Esempio di albero binario di ricerca
Quali operazioni? Ricerca di un elemento Ricerca del Minimo Ricerca del Massimo Ricerca del Successore/Predecessore Inserimento di un elemento Cancellazione di un elemento Bilanciamento (non tratteremo in questo corso)
Come avvenire la ricerca di un elemento? Elemento trovato!
Non è necessario visitare tutti i nodi, ma solo O(h) Dati in ingresso il puntatore alla radice dell albero e una chiave, l algoritmo restituisce il nodo con chiave uguale a k, oppure NIL se non esiste. Sfruttando la proprietà di ordinamento dell albero binario di ricerca, l algoritmo discende l albero in modo ricorsivo.
La ricerca può essere riscritta in forma iterativa
x k=18 Key[x]
x k=18 Key[x]
x k=18 Key[x]
x k=18 Key[x]
k=18 x Key[x]
x k=10 Key[x]
x k=10 Key[x]
x k=10 Key[x]
x k=10 Key[x]
x k=10 Key[x]
Ricerca del Minimo e del Massimo
Ricerca del Minimo e del Massimo Si sfrutta la proprietà dell'albero binario di ricerca. Partendo dal nodo x si ha che: - Se x ha un figlio sinistro, allora il minimo e nel sottoalbero sinistro, poichè per ogni nodo y in esso contenuto vale key[y]<key[x] - Se x non ha un figlio sinistro, allora per ogni nodo y contenuto nel sottoalbero destro vale key[y]>key[x]. Quindi, il minimo e x stesso minimo massimo
Ricerca del Minimo e del Massimo Qual è la complessità? La complessità in tempo per la ricerca del minimo e del massimo e pari all'altezza dell'albero, ossia O(h).
Ricerca del successore Il successore di un nodo x e definito come il nodo y con la più piccola chiave maggiore di key[x]: succ(key[x]) = min {y ϵ T : key[x] < key[y]} Supponiamo che nell'albero T ci siano solo chiavi distinte Sfruttando le proprietà dell'albero binario di ricerca si può trovare il successore di x senza dover confrontare le chiavi nei nodi
Ricerca del successore Se il nodo ha un figlio destro il successore di x è il minimo del sottoalbero destro Se il nodo non ha un figlio destro il successore di x è il più piccolo ascendente di x il cui figlio sinistro è anch'esso un ascendente di x. In pratica: si risale l'albero finchè il nodo di provenienza sta a sinistra. Il nodo di partenza risulta essere il massimo del sottoalbero sinistro di y. Quindi y e il suo successore.
Se x ha un figlio destro, e sufficiente cercare il minimo del sottoalbero destro. Esempio 1
Se x non ha un figlio destro, si risale l'albero fino a trovare la radice del sottoalbero di cui x e il massimo. Esempio 2 Il tempo necessario per trovare il successore e pari a O(h), dove h è l'altezza dell'albero. Si percorre un cammino non più lungo della distanza massima tra la radice e una foglia.
Homework - Predecessore Il predecessore di un nodo x e definito come il nodo y con la più grande chiave minore di key[x]: pred(key[x]) = max {y ϵ T : key[y] < key[x]} Si scriva lo pseudocodice dell algoritmo TREE-PREDECESSOR, il codice python, e si valuti il tempo computazionale
Inserimento e Rimozione Inserendo o rimuovendo un elemento la struttura dell'albero cambia L'albero deve mantenere le proprietà di un albero binario di ricerca La struttura dell'albero varia a seconda della sequenza di dati inseriti o rimossi L'inserimento è un'operazione semplice La rimozione è più complessa...ma non impossibile ;-)
Inserimento di una nuova chiave: Ricerca Posizione + Inserimento della foglia
Il tempo necessario e O(h): non più del cammino massimo tra la radice e una foglia
Servirà bilanciare l albero! (nella prossima lezione)
Rimozione Si possono verificare tre casi
Se z non ha figli, si modica p[z] in modo che punti non più a z, ma a NIL
Se z ha un unico figlio, si taglia fuori z dall'albero, facendo puntare p[z] all'unico figlio di z
Se z ha due figli, si individua il suo successore, ossia il minimo del suo sottoalbero destro. Quindi y prende il posto di z, e i dati in y vengono copiati nella posizione di z.
Se z ha due figli, si individua il suo successore, ossia il minimo del suo sottoalbero destro. Quindi y prende il posto di z, e i dati in y vengono copiati nella posizione di z.
Rimozione - considerazioni Se siamo nel caso 1 oppure 2 l'operazione di rimozione e immediata Se siamo nel caso 3 e necessario eseguire la procedura TREE -SUCCESSOR(z), che ha una complessità temporale O(h) Quindi la rimozione richiede tempo O(h)
Riepilogo L albero binario di ricerca è una struttura dati ispirata alla ricerca Le chiavi dei nodi del sottoalbero sinistro left[x] sono key[x] Le chiavi dei nodi del sottoalbero destro right[x] sono key[x] Operazioni: ricerca, minimo, massimo, prev, next, inserimento, e cancellazione Complessità Ricerca, Inserimento, Cancellazione sono O(h) per un albero di altezza h Un albero binario di ricerca con n nodi generato in maniera casuale ha un altezza O(log 2 n)