Esercizio 18chiave negativa più grande in un albero (2,4)
In questa pagina 5
Testo (esempio di tema d'esame, seconda parte, esercizio 2, 6 punti). Sia un (2,4)-Tree contenente entry con chiavi intere distinte.
(a) Progettare un algoritmo iterativo efficiente che determina la più grande chiave negativa in . Se in non esistono chiavi negative, l'algoritmo deve restituire "no negative key". (b) Analizzare la complessità dell'algoritmo del punto precedente.
Idea
Un (2,4) è un multi-way search tree con foglie tutte alla stessa profondità (vedi Multi-way search tree e alberi (2,4)Multi-way search tree (nodi con più entry, d figli e d-1 chiavi ordinate), ricerca in O(d_max h), un MWS tree con n entry ha n+1 foglie; albero (2,4): nodi con 2-4 figli e tutte le foglie alla stessa profondità, altezza Theta(log n) con dimostrazione, operazioni in Theta(log n); idea di overflow e underflow; tabella di confronto con gli alberi binari di ricerca.Multi-way search tree e alberi (2,4) →): in un nodo con chiavi e figli , le chiavi di stanno tra e . Si cerca il predecessore di (la chiave più grande minore di ) con una discesa guidata dalla ricerca di .
In un nodo :
- sia la più grande chiave negativa tra quelle di (se esiste). Allora è un candidato, ed eventuali chiavi negative maggiori di possono stare solo in , il sottoalbero tra e (le chiavi nei sottoalberi successivi sono , quelle nei precedenti sono ). Si aggiorna il candidato e si scende in ;
- se nessuna chiave di è negativa, tutte le chiavi sono e quelle negative possono stare solo nel primo sottoalbero (chiavi ): si scende in , senza toccare il candidato.
Si ripete fino a una foglia esterna; il candidato finale è la risposta (oppure "no negative key" se non è mai stato impostato).
(a) Pseudocodice
Algoritmo maxNegativeKey(T)
Input: (2,4)-tree T con chiavi intere distinte
Output: la più grande chiave negativa di T, oppure "no negative key"
cand <- null
v <- T.root()
while v non è una foglia do
siano k1 < k2 < ... < k_{d-1} le chiavi di v e v1, ..., vd i figli
j <- numero di chiavi negative di v (le chiavi negative sono k1..kj, perché sono ordinate)
if j >= 1 then cand <- k_j
v <- v_{j+1} (se j = 0: il primo figlio v_1)
if cand = null then return "no negative key"
else return candLe chiavi di un nodo sono ordinate, quindi le negative sono un prefisso e il confronto con si può fermare alla prima chiave non negativa: al più confronti per nodo.
Correttezza (invariante). All'inizio di ogni iterazione, se esiste una chiave negativa in più grande di cand (o qualunque chiave negativa, se cand è null), allora sta in . Vale all'inizio ( = radice, ). Nell'iterazione il candidato diventa la più grande chiave negativa di e si scende nell'unico sottoalbero che può contenerne di maggiori (ragionamento sopra), quindi l'invariante si conserva. Quando è una foglia esterna è vuoto, quindi cand è la più grande chiave negativa (o non ne esistono).
Esempio
Albero: radice con chiavi ; figli , e ; sotto di essi solo foglie esterne.
- Radice: negative ():
cand, si scende nel secondo figlio (chiavi tra e ). - Nodo : nessuna negativa ():
candinvariato, si scende nel primo figlio (foglia esterna): fine. Risultato: ✓ (le chiavi sono minori).
Se invece il secondo figlio fosse : nel secondo nodo , cand , si scende nel figlio tra e : foglia, risultato . Se tutte le chiavi sono , cand rimane null e si restituisce "no negative key". (Verificato con 2000 (2,4)-tree casuali, confrontando con il massimo delle chiavi negative.)
(b) Complessità
Si visita un solo nodo per livello, dalla radice a una foglia esterna, quindi al più nodi, con altezza. In un (2,4) ogni nodo ha al più chiavi, quindi il costo per nodo è . Poiché (vedi la dimostrazione in Multi-way search tree e alberi (2,4)Multi-way search tree (nodi con più entry, d figli e d-1 chiavi ordinate), ricerca in O(d_max h), un MWS tree con n entry ha n+1 foglie; albero (2,4): nodi con 2-4 figli e tutte le foglie alla stessa profondità, altezza Theta(log n) con dimostrazione, operazioni in Theta(log n); idea di overflow e underflow; tabella di confronto con gli alberi binari di ricerca.Multi-way search tree e alberi (2,4) →), la complessità è
Anzi è sempre : la discesa arriva comunque a una foglia esterna e tutte le foglie di un (2,4) sono alla stessa profondità . È molto meglio dell'alternativa di visitare tutto l'albero, .
Errori comuni
- Visitare tutto l'albero per cercare il massimo tra le chiavi negative: invece di .
- Scendere nel figlio sbagliato: dopo aver trovato la chiave negativa più grande si scende in (a destra di ), non in .
- Dimenticare di non cambiare il candidato quando un nodo non ha chiavi negative (ma di scendere comunque nel primo figlio).
- Non gestire il caso "nessuna chiave negativa".
Versione ripasso
Testo. (2,4)-Tree con chiavi intere distinte: algoritmo iterativo per la più grande chiave negativa (o "no negative key"); complessità.
- Idea (vedi Multi-way search tree e alberi (2,4)Multi-way search tree (nodi con più entry, d figli e d-1 chiavi ordinate), ricerca in O(d_max h), un MWS tree con n entry ha n+1 foglie; albero (2,4): nodi con 2-4 figli e tutte le foglie alla stessa profondità, altezza Theta(log n) con dimostrazione, operazioni in Theta(log n); idea di overflow e underflow; tabella di confronto con gli alberi binari di ricerca.Multi-way search tree e alberi (2,4) →): predecessore di . In un nodo con negative : se ,
cande si scende in ; se si scende in . - Pseudocodice:
cand <- null; mentre non è foglia: = numero di negative in , aggiornacand, ; restituiscecando "no negative key". - Invariante: una negativa migliore di
candsta in . - Esempio: radice , figli , , ⇒ risultato ; con secondo figlio ⇒ .
- Complessità: un nodo per livello, chiavi per nodo, ⇒ .
- Esempio: radice con figli , , : radice ⇒
cand = -5, scende nel secondo figlio; nodo senza negative ⇒ primo figlio (foglia): risultato . Se il secondo figlio fosse ⇒ . - Costo: nodi, al più confronti per nodo, sempre .
- Errori: visitare tutto (); figlio invece di ; caso "nessuna negativa" omesso.