Salta al contenuto
Note per Studenti Multi-way search tree e alberi (2,4)

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 Θ(h)\Theta(h) ma hh può essere proporzionale a nn. 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).

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 ≥2\ge 2 figli;
  • ogni nodo interno con d≥2d \ge 2 figli v1,…,vdv_1, \dots, v_d (dd-nodo) memorizza d−1d - 1 entry (k1,x1),…,(kd−1,xd−1)(k_1, x_1), \dots, (k_{d-1}, x_{d-1}) con k1<k2<⋯<kd−1k_1 < k_2 < \dots < k_{d-1};
  • per 1≤i≤d1 \le i \le d ogni chiave kk del sottoalbero TviT_{v_i} soddisfa ki−1<k<kik_{i-1} < k < k_i (con k0=−∞k_0 = -\infty, kd=+∞k_d = +\infty).

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 k1<k2<k3k_1 < k_2 < k_3 e quattro figli, con chiavi <k1< k_1 in v1v_1, in (k1,k2)(k_1, k_2) in v2v_2, in (k2,k3)(k_2, k_3) in v3v_3, >k3> k_3 in v4v_4.

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 vv con chiave kk. Complessità: il cammino ha lunghezza ≤h\le h e in ogni nodo si cerca tra ≤dmax\le d_{max} chiavi (se le entry di un nodo sono in una mappa secondaria, ad esempio una lista): O(dmax h)O(d_{max} \, h).

Esempio: radice (10,20)(10, 20) con figli (3,7)(3, 7), (14,17)(14, 17), (25,30,35)(25, 30, 35). Cercare 1717: tra 1010 e 2020 si va nel secondo figlio (14,17)(14, 17) e si trova. Cercare 2424: 24>2024 > 20, si scende nel terzo figlio; 24<2524 < 25, si scende nel suo primo figlio, che è una foglia: assente.

Numero di foglie

Proposizione. Un MWS tree con nn entry ha n+1n + 1 foglie.

Dimostrazione (induzione sull'altezza hh). Base h=0h = 0: la sola radice è una foglia, n=0n = 0, 11 foglia. Passo: TT di altezza h+1h+1 con radice dd-nodo, sottoalberi T1,…,TdT_1, \dots, T_d con nin_i entry e mim_i foglie, altezze ≤h\le h. Per ipotesi mi=ni+1m_i = n_i + 1. Allora n=(d−1)+∑nin = (d-1) + \sum n_i e m=∑mi=∑(ni+1)=d+∑ni=1+(d−1)+∑ni=n+1m = \sum m_i = \sum (n_i + 1) = d + \sum n_i = 1 + (d - 1) + \sum n_i = n + 1. □\square

(Se tutti i nodi interni fossero dd-nodi, l'albero sarebbe dd-ario e le foglie sarebbero (d−1)⋅(nodi interni)+1(d-1) \cdot (\text{nodi interni}) + 1, con (d−1)⋅(nodi interni)=(d-1) \cdot (\text{nodi interni}) = numero di entry.)

Alberi (2,4)

Un albero (2,4) è un MWS tree tale che:

  1. ogni nodo interno è un dd-nodo con 2≤d≤42 \le d \le 4 (cioè ha 11, 22 o 33 entry);
  2. tutte le foglie hanno la stessa profondità.

Proposizione. Un (2,4) con n>0n > 0 entry ha altezza Θ(log⁡n)\Theta(\log n).

Dimostrazione. Sia hh l'altezza (= livello delle foglie) e mim_i il numero di nodi al livello ii. Si ha m0=1m_0 = 1 e, poiché ogni nodo interno ha tra 22 e 44 figli e le foglie sono tutte a livello hh, 2i≤mi≤4i2^i \le m_i \le 4^i. In particolare 2h≤mh≤4h2^h \le m_h \le 4^h. Ma mh=n+1m_h = n + 1 (proposizione sulle foglie). Quindi n+1≥2h⇒h≤log⁡2(n+1)n + 1 \ge 2^h \Rightarrow h \le \log_2(n+1) e n+1≤4h⇒h≥12log⁡2(n+1)n + 1 \le 4^h \Rightarrow h \ge \frac12 \log_2(n+1). Dunque h∈Θ(log⁡n)h \in \Theta(\log n). □\square

Corollario. In un (2,4) con nn entry MWTreeSearch e get costano Θ(log⁡n)\Theta(\log n) (ogni nodo ha ≤3\le 3 chiavi, dmaxd_{max} è costante). Anche put e remove si implementano in Θ(log⁡n)\Theta(\log n); la loro implementazione non è richiesta all'esame ma l'idea è semplice:

  • Inserimento: si cerca la foglia ww e si inserisce la chiave nel nodo vv padre di ww. Se vv 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 33 figli) e l'ultima forma l'altro (a 22 figli). L'overflow può propagarsi verso la radice; se la radice si spezza, nasce una nuova radice e l'altezza cresce di 11 (tutte le foglie scendono insieme: la condizione 2 resta vera). Esempio: inserendo 2626 nel nodo (25,30,35)(25, 30, 35) si ha (25,26,30,35)(25, 26, 30, 35): si spezza in (25,26)(25, 26) e (35)(35) e 3030 sale nella radice, che diventa (10,20,30)(10, 20, 30).
  • 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 33 figli oppure una fusione con un fratello a 22 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 (k,Lk)(k, L_k), o modificando ABR e (2,4) per ammettere chiavi uguali.

Confronto

Metodo ABR (2,4)
get(k) Θ(h)\Theta(h) Θ(log⁡n)\Theta(\log n)
put(k, v) Θ(h)\Theta(h) Θ(log⁡n)\Theta(\log n)
remove(k) Θ(h)\Theta(h) Θ(log⁡n)\Theta(\log n)
remove(k, v) (dizionario) Θ(s+h)\Theta(s + h) Θ(s+log⁡n)\Theta(s + \log n)

(ss = numero di valori associati alla chiave.) Nell'ABR hh può essere n−1n - 1; 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 nn entry ha n+1n+1 foglie vuote.
  • Cercare linearmente i figli come in un ABR: in un dd-nodo si cerca l'intervallo ki−1<k≤kik_{i-1} < k \le k_i tra d−1d - 1 chiavi.
  • Stimare la complessità come Θ(h)\Theta(h) senza specificare h=Θ(log⁡n)h = \Theta(\log n) per i (2,4).

Versione ripasso

Esercizi su questo argomento

Teoria collegata