Multi-way search tree e alberi (2,4)
In questa pagina 5
Problema degli ABR (vedi Alberi binari di ricercaAlbero binario di ricerca come albero binario proprio con entry nei nodi interni e foglie vuote; inorder crescente; TreeSearch; get, put e remove (due casi, con predecessore inorder) in Theta(h); altezza fino a n-1; esempi di inserimenti; alberi aumentati con campi size e max e algoritmi di conteggio e interrogazione in O(h).Alberi binari di ricerca →): get, put, remove costano ma può essere proporzionale a . Due rimedi: ristrutturare l'albero quando lo sbilanciamento supera una soglia (AVL, alberi rosso-neri, non trattati) oppure rendere i nodi più capienti e usare la capienza per assorbire ingressi e uscite di entry: gli alberi (2,4). L'idea dei nodi capienti è la stessa dei B-tree usati nei database e nei file system: un nodo corrisponde a un blocco letto con un solo accesso a un disco (Memoria esterna - dischi, RAID e memorie otticheDisco magnetico (piatti, facce, tracce, settori, cilindri); tempo di accesso come somma di posizionamento, latenza rotazionale e trasferimento, con formule ed esempio; algoritmi di scheduling FCFS, SSTF e ascensore; livelli RAID da 0 a 6; SSD; CD, DVD e nastri.Memoria esterna - dischi, RAID e memorie ottiche →, Gerarchia di memoria e principio di localitàCaratteristiche delle memorie (posizione, capacità, unità di trasferimento, metodo di accesso, prestazioni, volatilità); compromesso costo-capacità-velocità e gerarchia a livelli; località temporale e spaziale con esempi; hit, miss e tempo medio di accesso con calcolo svolto.Gerarchia di memoria e principio di località →), quindi conviene avere pochi livelli e molte chiavi per nodo.
Multi-way search tree
Definizione (multi-way search tree). Un multi-way search tree (MWS tree) è un albero ordinato (vedi AlberiAlbero radicato (definizione per padre e ricorsiva), terminologia (antenati, discendenti, nodi interni ed esterni, sottoalbero, albero ordinato), profondità, livello, altezza; altezza = massima profondità delle foglie; algoritmi depth e height con costo; somma dei figli = n-1; esempio di algoritmo Omega(n^2) (heightBad).Alberi →) in cui:
- ogni nodo interno ha figli;
- ogni nodo interno con figli (-nodo) memorizza entry con ;
- per ogni chiave del sottoalbero soddisfa (con , ).
Esempio. Un -nodo con chiavi ha figli, con chiavi , in e . Il caso è il nodo dell'ABR (Alberi binari di ricercaAlbero binario di ricerca come albero binario proprio con entry nei nodi interni e foglie vuote; inorder crescente; TreeSearch; get, put e remove (due casi, con predecessore inorder) in Theta(h); altezza fino a n-1; esempi di inserimenti; alberi aumentati con campi size e max e algoritmi di conteggio e interrogazione in O(h).Alberi binari di ricerca →): una chiave e due sottoalberi, uno con chiavi minori e uno con chiavi maggiori. Gli intervalli aperti sono quelli dei intervalli di numeri realiNaturali, interi, razionali e reali, perché la radice di 2 obbliga a passare da Q a R, e gli intervalli.Insiemi numerici (N, Z, Q, R) →: gli intervalli coprono tutta la retta tranne le chiavi del nodo, quindi ogni chiave cercata ha esattamente un posto dove andare.
Per convenzione, come negli ABR, le foglie non memorizzano entry. Un ABR è il caso in cui ogni nodo interno è un 2-nodo.
Esempio di 4-nodo: tre chiavi e quattro figli, con chiavi in , in in , in in , in .
Ricerca
Algoritmo MWTreeSearch(k, v)
Input: chiave k, nodo v Output: nodo di T_v con la chiave k, o la foglia "giusta" per k
if T.isExternal(v) then return v
siano (k1,x1), ..., (k_{d-1}, x_{d-1}) le entry di v
trova i con k_{i-1} < k <= k_i (k_0 = -infinito, k_d = +infinito)
if k = k_i then return v
else return MWTreeSearch(k, v_i)get(k): cerca come sopra; se il risultato è una foglia restituisce null, altrimenti la entry in con chiave . Complessità: il cammino ha lunghezza e in ogni nodo si cerca tra chiavi (se le entry di un nodo sono in una mappa secondaria, ad esempio una lista): .
Esempio: radice con figli , , . Cercare : tra e si va nel secondo figlio e si trova. Cercare : , si scende nel terzo figlio; , si scende nel suo primo figlio, che è una foglia: assente.
Numero di foglie
Proposizione (numero di foglie di un MWS tree). Un MWS tree con entry ha foglie.
Esempio. Con radice e figli , , le entry sono e le foglie .
Dimostrazione (induzione sull'altezza , vedi Principio di induzionePer dimostrare una proprietà per ogni n basta il passo base e il passo induttivo da n a n+1.Principio di induzione →). Base : la sola radice è una foglia, , foglia. Passo: di altezza con radice -nodo, sottoalberi con entry e foglie, altezze . Per ipotesi . Allora e .
(Se tutti i nodi interni fossero -nodi, l'albero sarebbe -ario e le foglie sarebbero , con numero di entry.)
Alberi (2,4)
Definizione (albero (2,4) e altezza). Un albero (2,4) è un MWS tree tale che:
- ogni nodo interno è un -nodo con (cioè ha , o entry);
- tutte le foglie hanno la stessa profondità.
Proposizione. Un (2,4) con entry ha altezza .
Esempio. Con entry l'altezza è tra e , cioè .
Dimostrazione. Sia l'altezza (= livello delle foglie) e il numero di nodi al livello . Si ha e, poiché ogni nodo interno ha tra e figli e le foglie sono tutte a livello , . In particolare . Ma (proposizione sulle foglie). Quindi e . Dunque .
I passaggi sui logaritmi: si inverte applicando , funzione crescente (Esponenziale e logaritmoLa funzione esponenziale a^x (base positiva diversa da 1) e la sua inversa, il logaritmo in base a, con grafici e proprietà.Esponenziale e logaritmo →), e dà ; dà , cioè . Il grafico mostra la fascia in cui sta l'altezza di un (2,4) con entry: per è tra e , mentre un ABR degenere avrebbe altezza .
Grafico interattivo: Altezza di un albero (2,4) con n entry: compresa tra metà di log2(n+1) (tutti 4-nodi) e log2(n+1) (tutti 2-nodi); per n = 1000 tra 5 e 10
Controllo sull'esempio della ricerca (radice con tre figli): , altezza ; le foglie sono e valgono .
Corollario. In un (2,4) con entry MWTreeSearch e get costano (ogni nodo ha chiavi, è costante). Anche put e remove si implementano in ; la loro implementazione non è richiesta all'esame ma l'idea è semplice:
- Inserimento: si cerca la foglia e si inserisce la chiave nel nodo padre di . Se diventa un 5-nodo (4 chiavi, overflow) lo si spezza: la terza delle quattro chiavi sale al padre, le prime due restano in un nodo (a figli) e l'ultima forma l'altro (a figli). L'overflow può propagarsi verso la radice; se la radice si spezza, nasce una nuova radice e l'altezza cresce di (tutte le foglie scendono insieme: la condizione 2 resta vera). Esempio: inserendo nel nodo si ha : si spezza in e e sale nella radice, che diventa .
Perché la condizione 2 resta vera: lo spezzamento non cambia la profondità delle foglie (i nuovi nodi sono allo stesso livello del vecchio) e la salita della chiave aumenta di i figli del padre senza cambiare livelli. Inoltre i due nodi nati dallo spezzamento hanno e figli, quindi rispettano il vincolo . Sequenza completa di inserimenti partendo dall'albero vuoto (una sola foglia):
| inserimento | albero dopo | note |
|---|---|---|
| la foglia diventa nodo interno con due foglie | ||
| 3-nodo | ||
| 4-nodo, ancora valido | ||
| radice con figli e | overflow: la terza chiave sale e crea una nuova radice, altezza | |
| radice , figli e | , si va a destra | |
| radice , figli e | ||
| radice , figli , , | overflow: sale nella radice |
In ogni istante le foglie sono tutte alla stessa profondità, e l'altezza è passata da a solo quando si è spezzata la radice.
- Rimozione: una entry di un nodo non terminale si sostituisce con il predecessore inorder, poi si toglie la entry da un nodo con foglie come figli. Se il nodo rimane senza entry (underflow) si fa un trasferimento da un fratello con almeno figli oppure una fusione con un fratello a figli (che può propagare l'underflow in su; se la radice si svuota, l'altezza diminuisce).
Dizionario con alberi di ricerca
Un dizionario (multimap, vedi Mappe e dizionariADT mappa (chiavi distinte) con get, put, remove, keySet/values/entrySet; famiglia mappa/mappa ordinata/dizionario (multimappa); applicazioni; implementazioni semplici ma poco efficienti (lista, array indicizzato dalle chiavi); dizionario realizzato con una mappa di liste.Mappe e dizionari →) si realizza o con una mappa di coppie , o modificando ABR e (2,4) per ammettere chiavi uguali.
Confronto
| Metodo | ABR | (2,4) |
|---|---|---|
get(k) |
||
put(k, v) |
||
remove(k) |
||
remove(k, v) (dizionario) |
( = numero di valori associati alla chiave.) Nell'ABR può essere ; nel (2,4) il bilanciamento è garantito dalla struttura.
Errori comuni
- Dimenticare la condizione "tutte le foglie alla stessa profondità": senza di essa l'altezza non è logaritmica.
- Contare le foglie come entry: un MWS tree con entry ha foglie vuote.
- Cercare linearmente i figli come in un ABR: in un -nodo si cerca l'intervallo tra chiavi.
- Stimare la complessità come senza specificare per i (2,4).
Versione ripasso
- Perché: negli ABR può essere (vedi Alberi binari di ricercaAlbero binario di ricerca come albero binario proprio con entry nei nodi interni e foglie vuote; inorder crescente; TreeSearch; get, put e remove (due casi, con predecessore inorder) in Theta(h); altezza fino a n-1; esempi di inserimenti; alberi aumentati con campi size e max e algoritmi di conteggio e interrogazione in O(h).Alberi binari di ricerca →). I nodi capienti degli alberi (2,4) tengono l'altezza logaritmica; sono l'idea dei B-tree dei database e dei file system, dove un nodo è un blocco di disco (Gerarchia di memoria e principio di localitàCaratteristiche delle memorie (posizione, capacità, unità di trasferimento, metodo di accesso, prestazioni, volatilità); compromesso costo-capacità-velocità e gerarchia a livelli; località temporale e spaziale con esempi; hit, miss e tempo medio di accesso con calcolo svolto.Gerarchia di memoria e principio di località →).
- MWS tree: albero ordinato in cui ogni nodo interno con figli è un -nodo con entry ; il figlio contiene chiavi con (con , ). Le foglie non memorizzano entry. Un ABR è il caso in cui tutti i nodi interni sono 2-nodi.
- Ricerca
MWTreeSearch(k, v): se è esterno restituisce ; altrimenti trova con ; se restituisce , altrimenti ricorre su . Costo . - Esempio: radice con figli , , . Cercare dà il nodo ; cercare arriva in una foglia: assente.
- Proposizione: un MWS tree con entry ha foglie. Induzione sull'altezza: se il sottoalbero ha entry e foglie, la radice con figli ha . Nell'esempio: .
- Alberi (2,4): MWS tree con nodi di , o figli (da a entry) e tutte le foglie alla stessa profondità. Al livello ci sono nodi e , quindi : .
- Costi:
get,put,removein (vedi Mappe e dizionariADT mappa (chiavi distinte) con get, put, remove, keySet/values/entrySet; famiglia mappa/mappa ordinata/dizionario (multimappa); applicazioni; implementazioni semplici ma poco efficienti (lista, array indicizzato dalle chiavi); dizionario realizzato con una mappa di liste.Mappe e dizionari →). Inserimento: se un nodo diventa un 5-nodo (overflow) si spezza, la terza chiave sale al padre e, se arriva alla radice, l'altezza cresce di . Esempio: inserire in dà , spezzato in e , con che sale nella radice. La rimozione con underflow (trasferimento o fusione) non è richiesta all'esame. - Confronto: ABR , (2,4) per
get,puteremove. Per il dizionario,remove(k,v)costa contro , con valori associati alla chiave. - Inserimento senza overflow: se la foglia ha meno di entry, la chiave si aggiunge e basta; nessuna foglia cambia profondità.
- Sequenza: inserendo si ottiene la radice con figli e : l'altezza passa da a solo quando si spezza la radice.
- Errori tipici: dimenticare "foglie alla stessa profondità"; contare le foglie come entry (sono foglie vuote); cercare i figli come in un ABR invece che nell'intervallo .