Salta al contenuto
Note per Studenti Esercizio 17 · terremoto forte recente in un albero di ricerca

Esercizio 17terremoto forte recente in un albero di ricerca

Esame
In questa pagina 5

Testo (scritti del 19/09/2023 e del 04/09/2024, seconda parte, esercizio 2, 7 punti; compare anche in un esempio di tema d'esame). Il Dipartimento della Protezione Civile vuole aggiornare la classificazione sismica del territorio italiano, in base all'intensità e frequenza dei terremoti del passato. Per farlo utilizza un albero binario di ricerca TT, che implementa una mappa le cui entry sono coppie (t,it)(t, i_t), dove tt (la chiave) rappresenta un istante di tempo in cui è avvenuto un terremoto, e iti_t (il valore) rappresenta l'intensità del terremoto. Per ogni nodo v∈Tv \in T esiste un campo v.max che riporta la massima intensità dei terremoti rappresentati dalle entry di TvT_v (sottoalbero con radice vv). Si progetti un algoritmo ricorsivo TerremotoForteRecente (TFR) che, dati un tempo tt e un valore di intensità ii, restituisce yes se c'è stato un terremoto di intensità ≥i\ge i in un istante di tempo ≥t\ge t, altrimenti restituisce no.

(a) Spiegare l'idea alla base dell'algoritmo, aiutandosi con un esempio numerico. (b) Specificare chiaramente l'input e l'output dell'algoritmo. (c) Scrivere l'algoritmo in pseudocodice. (d) Analizzare la complessità dell'algoritmo del punto precedente.


(a) Idea

Si cerca una entry (t′,i′)(t', i') con t′≥tt' \ge t e i′≥ii' \ge i (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 →). La struttura aiuta in due modi:

  • ordine delle chiavi: in un nodo vv con chiave kk, se k<tk < t allora vv e tutto il suo sottoalbero sinistro hanno chiavi <t< t e vanno scartati; si prosegue solo a destra. Se k≥tk \ge t, tutto il sottoalbero destro ha chiavi >k≥t> k \ge t e quindi basta il suo max;
  • campo max: se v.max <i< i nessuna entry di TvT_v può avere intensità ≥i\ge i, e si scarta tutto il sottoalbero in tempo costante.

Esempio. Le entry (t,it)(t, i_t) sono (10,4)(10, 4), (5,7)(5, 7), (15,3)(15, 3), (2,2)(2, 2), (8,9)(8, 9), inserite in questo ordine: radice 1010; figli 55 e 1515; 55 ha figli 22 e 88. I campi max sono: 2→22 \to 2, 8→98 \to 9, 5→max⁡(7,2,9)=95 \to \max(7, 2, 9) = 9, 15→315 \to 3, radice →9\to 9.

  • TFR(t=9,i=8)(t = 9, i = 8): radice: max =9≥8= 9 \ge 8; la chiave 10≥910 \ge 9 ma il valore 4<84 < 8: si prova a sinistra. Nodo 55: max =9≥8= 9 \ge 8; chiave 5<95 < 9, si va solo a destra. Nodo 88: max =9≥8= 9 \ge 8; chiave 8<98 < 9, si va a destra: foglia vuota, no. Tornati alla radice si prova a destra (nodo 1515): max =3<8= 3 < 8, no. Risultato: no (il terremoto di intensità 99 è avvenuto al tempo 8<98 < 9).
  • TFR(t=7,i=8)(t = 7, i = 8): radice →\to nodo 55 (chiave 5<75 < 7, solo a destra) →\to nodo 88: chiave 8≥78 \ge 7 e valore 9≥89 \ge 8: yes.

(b) Input e output

Input: un nodo vv di TT (alla prima chiamata la radice; null/foglia esterna per il sottoalbero vuoto), un tempo tt, un'intensità ii. Output: yes se TvT_v contiene una entry con chiave ≥t\ge t e valore ≥i\ge i, no altrimenti.

(c) Pseudocodice

Algoritmo TFR(v, t, i)
Input: nodo v di T (null se il sottoalbero è vuoto), tempo t, intensità i
Output: yes se in T_v c'è una entry (t', i') con t' >= t e i' >= i, no altrimenti
if v = null OR v.max < i then return no
if v.key >= t then
    if v.value >= i then return yes
    if TFR(v.left, t, i) = yes then return yes
return TFR(v.right, t, i)

Chiamata: TFR(T.root(), t, i). Correttezza (induzione sull'altezza di vv): se vv è vuoto o v.max <i< i la risposta è no; altrimenti, se v.key≥tv.key \ge t, vv stesso è una entry valida quando v.value≥iv.value \ge i; il sottoalbero sinistro può contenere chiavi ≥t\ge t (si cerca ricorsivamente); il destro ha tutte le chiavi ≥t\ge t e si cerca ricorsivamente. Se v.key<tv.key < t, né vv né il suo sottoalbero sinistro possono contenere chiavi ≥t\ge t e si cerca solo a destra.

(d) Complessità

Sia hh l'altezza di TT. I nodi in cui l'algoritmo prosegue "a cavallo" di tt formano un unico cammino dalla radice (a sinistra quando v.key≥tv.key \ge t, a destra quando v.key<tv.key < t). Da ciascun nodo del cammino con v.key≥tv.key \ge t parte una seconda chiamata sul figlio destro, che ha tutte le chiavi ≥t\ge t:

  • se il suo max è <i< i la chiamata termina subito con no in O(1)O(1);
  • altrimenti nel sottoalbero esiste una entry valida, e la discesa lungo i nodi con max ≥i\ge i (controllo del valore, poi a sinistra se il max di sinistra è ≥i\ge i, altrimenti a destra) la trova restituendo yes dopo al più hh passi; quando ciò accade tutta la ricorsione termina.

In totale O(h)+O(h)=O(h)O(h) + O(h) = O(h) operazioni, ciascuna Θ(1)\Theta(1). La complessità è O(h)O(h): O(log⁡n)O(\log n) se l'albero è bilanciato, O(n)O(n) nel caso pessimo di albero a catena. (Verificato su 500 alberi casuali confrontando il risultato con la ricerca esaustiva.)

Errori comuni

  • Visitare tutto l'albero (Θ(n)\Theta(n)) senza sfruttare né l'ordine né max.
  • Usare solo il campo max e ignorare la condizione sul tempo (si restituirebbe yes per un terremoto troppo vecchio).
  • Cercare nel sottoalbero sinistro quando v.key<tv.key < t (inutile) o dimenticare di cercare a sinistra quando v.key≥tv.key \ge t e v.value<iv.value < i.
  • Non specificare cosa fa l'algoritmo su un sottoalbero vuoto.

Versione ripasso

Testo. ABR con entry (t,it)(t, i_t) (istante, intensità), campo v.max = massima intensità in TvT_v. TFR(t, i) = yes se esiste un terremoto con intensità ≥i\ge i al tempo ≥t\ge t. Idea con esempio, input/output, pseudocodice, complessità.

  • Idea (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 →): se v.key<tv.key < t si va solo a destra; se v.key≥tv.key \ge t il sottoalbero destro è tutto ≥t\ge t; se v.max<iv.max < i si scarta il sottoalbero.
  • Esempio: entry (10,4),(5,7),(15,3),(2,2),(8,9)(10,4), (5,7), (15,3), (2,2), (8,9); TFR(9,8)\text{TFR}(9, 8) = no, TFR(7,8)\text{TFR}(7, 8) = yes.
  • Pseudocodice: v = null o v.max < i ⇒ no; se v.key >= t: v.value >= i ⇒ yes, TFR(left) = yes ⇒ yes; infine return TFR(right).
  • Complessità: un cammino a cavallo di tt più al più una discesa che termina con yes: O(h)O(h).
  • Esempio completo: max dei nodi: 2→22 \to 2, 8→98 \to 9, 5→95 \to 9, 15→315 \to 3, radice →9\to 9. TFR(9,8)\text{TFR}(9, 8): radice (10≥910 \ge 9, valore 4<84 < 8) ⇒ sinistra: nodo 55 (5<95 < 9, solo a destra) ⇒ nodo 88 (8<98 < 9, destra vuota) ⇒ no; poi destra: nodo 1515 con max 3<83 < 8 ⇒ no. TFR(7,8)\text{TFR}(7, 8): nodo 88 ha chiave 8≥78 \ge 7 e valore 9≥89 \ge 8 ⇒ yes.
  • Perché serve max: senza di esso, per decidere su TvT_v bisognerebbe guardarne tutte le entry (Θ(n)\Theta(n)); con max un sottoalbero tutto nell'intervallo di tempo si scarta o si accetta in O(1)O(1) (se max <i< i lo si scarta, altrimenti esiste certamente una entry valida e la discesa la trova).
  • Input e output: input nodo vv, tempo tt, intensità ii; output yes/no; sottoalbero vuoto ⇒ no.
  • Errori: visitare tutto l'albero; ignorare il tempo; cercare a sinistra quando v.key<tv.key < t.

Teoria collegata