Binary Search Trees ( 10.1) Binary Search Trees AVL Trees Multy-ay Search Trees < > 1 4 = (,4) Trees External Searching Red-Black Trees 1 Dictionary ADT (.3) L ADT dizionario (Dictionary ADT) modella una collezione di coppie (key, element), dette entry, su cui sono possibili operazioni di ricerca Le operazioni principali di un dizionario sono la ricerca, l inserimento e la rimozione di entry Sono consentiti più entry distinte con lo stesso valore della key Due tipi dizionari: Unordered Ordered 1
Dictionary ADT (.3) Metodi dell ADT Dictionary: find (k): ritorna l entry con il valore di chiave k, se esiste, altrimenti ritorna null findall (k): ritorna una collezione iterable su tutte le entry con chiave k insert (k, v): inserisce e ritorna l entry (k, v) remove (e): rimuove l entry e dal dizionario entries (): ritorna una collezione iterable di entries size () isempty () 3 Ordered Dictionaries (.5.) Si suppone che sia definito un ordinamento totale sulle chiavi Nuove operazioni basate sull ordinamento: first (): la prima entry nel dizionario rispetto all ordinamento last (): l ultima entry nel dizionario rispetto all ordinamento successors (k): ritorna un iteratore sulle entries con chiavi maggiori_di od eguali a k: ordinamento non decrescente predecessors (k): ritorna un iteratore sulle entries con chiavi minori di o eguali a k: ordinamento non crescente 4
Binary Search (.3.3) L algoritmo di Ricerca Binaria può essere utilizzato per l operazione find(k) se il dizionario è implementato come una sequenza basata su array ordinata rispetto alle chiavi: ad ogni passo, la cardinalità dell insieme su cui effettuare la ricerca è dimezzata l algoritmo termina dopo O(log n) passi Esempio: find(7) 0 l 0 l 0 0 1 3 4 5 7 11 14 1 1 1 m h 1 3 4 5 7 11 14 1 1 1 m h 1 3 4 5 7 11 14 1 1 1 l m h 1 3 4 5 7 11 14 1 1 1 l=m =h 5 Search Tables (.3.3) Una search table è un dizionario implementato mediante una sequenza ordinata Le entries del dizionario vengono memorizzate in una sequenza basata su array e ordinata rispetto ai valori delle chiavi per confrontare le chiavi viene usato un comparator esterno Performance: find richiede O(log n) time, usando la ricerca binaria insert richiede O(n) time, poiché mediamente è necessario spostare n/ items per far posto alla nuova entry remove richiede O(n) time, poiché mediamente è necessario spostare n/ entry per compattare le entries dopo la rimozione 3
Binary Search Trees ( 10.1) Un binary search tree è un binary tree in cui i nodi interni contengono le entries (key, value) e che soddisfa alle seguente proprietà d ordine totale: se u, v, e sono tre nodi dell albero tali che u è nel sottoalbero sinistro di v e è nel sottoalbero destro di v risulta key(u) key(v) key() I nodi esterni non contengono entries Un attraversamento nell in-ordine di un albero binario di ricerca visita le chiavi in ordine non decrescente v u 1 4 7 Algoritmo di Search ( 10.1.1) Per cercare una chiave k, si percorre un cammino che inizia nella radice e scende verso i nodi esterni dell albero Il nodo successivo da visitare è determinato dall esito del confronto della chiave k con la chiave del nodo corrente Se la chiave non è presente nell albero la ricerca ha termine in un nodo esterno, Esempio: find(4): TreeSearch(4,root) Algorithm TreeSearch(k, v) if T.isExternal (v) return v if k < key(v) return TreeSearch(k, T.left(v)) 1 4 else if k > key(v) return TreeSearch(k, T.right(v)) else // k = key(v) return v 4
Algoritmo di Search iterativo ( 10.1.1) Equivalente algoritmo iterativo per la ricerca: Algorithm TreeSearch(k, v) hile (! T.isExternal (v) ) if k < key(v) v= T.left(v) else if k > key(v) v= T.right(v) else break; // k = key(v) return v 1 4 Analisi complessità di Search Nel caso più sfavorevole (chiave non trovata) la lunghezza del cammino percorso è pari all altezza h dell albero il numero di operazioni primitive effettuate in corrispondenza ad ogni chiamata ricorsiva (ad ogni nodo visitato) è costante, O(1) il cammino di ricerca più lungo ha al massimo h+1 nodi per cui il costo totale è O(h) con O(log n) < h < O(n) Height h Tree T Time per level O(1) O(1) O(1) Total time: O(h) 10 5
Inserimento ( 10.1.) Per eseguire insert(k, e), si cerca la chiave k usando TreeSearch Si assume che la chiave k non sia già nell albero, e che sia il nodo esterno in cui ha termine la ricerca Si inserisce k nel nodo e si trasforma in nodo interno Esempio: insert 5 < > 1 4 > 1 4 5 11 Algoritmo di Inserimento Algorithm TreeInsert( k, x, v ) Input: k chiave di ricerca, x valore associato a k, v un nodo di T Output: un nuovo nodo nel sottoalbero T(v) contenente l entry (k,x) TreeSearch(k,v) if k = key() then return TreeInsert(k, x, T.left(v)) T.insertAtExternal (, (k, x) ) return insertatexternal (v, e) : trasforma il nodo esterno v in un nodo interno contenente l entry e 1
Rimozione ( 10.1.) Per poter effettuare l operazione di remove(k), dobbiamo prima cercare la chiave k nell albero Supponiamo che la chiave k sia nell albero e che v sia il nodo contenente k Se il nodo v ha come figlio sinistro (destro) un nodo esterno, rimuoviamo v e dall albero con il metodo removeexternal() Esempio: remove 4 < > 1 4 v 5 1 5 13 Rimozione (cont.) Consideriamo il caso in cui la chiave k da rimuovere è contenuta in un nodo v i cui figli sono entrambi nodi interni: cerchiamo il nodo successore nell inordine del nodo v copiamo key() nel nodo v rimuoviamo il nodo e il suo figlio sinistro z (che deve essere un nodo esterno) mediante l operazione removeexternal(z) Esempio: remove 3 1 3 v 1 5 v z 5 14 7
Prestazioni Consideriamo un dizionario con n items implementato mediante un albero binario di ricerca di altezza h lo spazio utilizzato è O(n) i metodi find, insert e remove richiedono O(h) time L altezza h è O(n) nel caso più sfavorevole e O(log n) nel caso più favorevole 15 Implementazione Binary Search Tree Richiamo: LocationAareEntry BSTEntry implements Entry BinarySearchTree extends LinkedBinaryTree Metodi di servizio: checkkey treesearch per find, findall, insert insertatexternal removeexternal 1
Estende la classe LinkedBinaryTree public class BinarySearchTree<K,V> extends LinkedBinaryTree<Entry<K,V>> implements Dictionary<K,V> { protected Comparator<K> C; //comparator // actionpos : insertion node or parent of removed node protected Position<Entry<K,V>> actionpos; protected int numentries = 0; //number of entries public BinarySearchTree ( Comparator<K> c ) { //costruttore C = c; addroot(null); 17 Estende la classe LinkedBinaryTree T (BinarySearchTree) BinarySearchTree extends LinkedBinaryTree actionpos numentries C root size LinkedBinaryTree ExternalNode Oggetto Comparator 1
Location-aare BSTEntry // Nested class for location-aare binary search tree entries protected static class BSTEntry<K,V> implements Entry<K,V> { protected Kkey; b protected Vvalue; protected Position<Entry<K,V>> pos; //....... public K getkey() { return key; public V getvalue() { return value; public Position<Entry<K,V>> position() { return pos; c 1 Metodi di accesso // Extract the key of the entry at a given node of the tree protected Kkey(Position<Entry<K,V>> position) { return position.element() ).getkey(); protected Vvalue(Position<Entry<K,V>> position) { return position.element() ).getvalue(); protected Entry<K,V> entry (Position<Entry<K,V>> position) { return position.element(); p protected void replaceentry( Position<Entry<K,V>> p, Entry<K,V> ent) { ( (BSTEntry<K,V>) ent).pos = p; replace(p, ent); g 5 e ent 0 10
Metodi ausiliari //Auxiliary method for inserting an entry at an external node protected Entry<K,V> insertatexternal ( Position<Entry<K,V>> v, Entry<K,V> e ) { expandexternal(v,null,null); //metodo ereditato replace(v, e); numentries++; return e; //Auxiliary method for removing an external node and its parent protected void removeexternal ( Position<Entry<K,V>> v ) { removeaboveexternal(v); //metodo ereditato numentries--; 1 Metodi ausiliari //Auxiliary method used by find, insert, and remove protected Position<Entry<K,V>> treesearch ( K key, Position<Entry<K,V>> pos ) { if ( isexternal(pos) ) return pos; //key not found else { K curkey = key( pos ); int comp = C.compare(key, curkey); if (comp < 0) return treesearch(key, left(pos)); //left subtree else if (comp > 0) return treesearch(key, right(pos)); //right subtree return pos; //return internal node here key is found 11
Metodo find public Entry<K,V> find (K key) thros InvalidKeyException { checkkey(key); //may thro an InvalidKeyException Position<Entry<K,V>> curpos = treesearch( key, root() ); actionpos = curpos; //node here the search ended if ( isinternal(curpos) ) return entry(curpos); return null; 3 Metodo insert public Entry<K,V> insert ( K k, V x ) thros InvalidKeyException { checkkey(k); //may thro an InvalidKeyException Position<Entry<K,V>> inspos = treesearch (k, root()); hile (! isexternal ( inspos ) ) // iterative search for insert pos inspos = treesearch (k, left(inspos)); actionpos = inspos; //node here the ne entry is being inserted return insertatexternal (inspos, ne BSTEntry (k, x, inspos) ); 4 1
Metodo remove (1/) public Entry<K,V> remove (Entry<K,V> ent) thros InvalidEntryException { checkentry(ent); //may thro an InvalidEntryException Position<Entry<K,V>> rempos = ((BSTEntry<K,V>) ent).position(); Entry<K,V> toreturn = entry(rempos); //entry to be returned if ( isexternal ( left(rempos) ) ) rempos = left(rempos); //left easy case else if ( isexternal ( right(rempos) ) ) rempos = right(rempos); //right easy case else { // entry is at a node ith internal children.......... 5 Metodo remove (/) else { // entry is at a node ith internal children //find node for moving entry Position<Entry<K,V>> sappos = rempos; rempos = right(sappos); do rempos = left(rempos); hile ( isinternal (rempos) ); replaceentry<k,v>( sappos, (Entry<K,V>) parent(rempos).element() ); actionpos = sibling (rempos); //sibling of the leaf to be removed removeexternal (rempos); return toreturn; 13