Esercizi su alberi binari Esercizi svolti: Determinazione nodi contenti verifica completezza verifica quasi completezza lunghezza del cammino interno determinazione ultima foglia in un quasi completo verifica de bilanciamento in altezza. Esercizio proposto: individuazione di un cammino radice foglia la cui somma delle chiavi è uguale a un valore dato in input Prof. E. Fachini - Intr. Alg. 1
Numero di nodi contenti Si definisca un algoritmo ricorsivo che dà in output il numero di nodi contenti nel'albero di input, se non è vuota e -1 altrimenti. Un nodo e' contento se nell'albero in esso radicato ci sono piu' nodi figli sinistri che destri. Prof. E. Fachini - Intr. Alg. 2
nodi contenti non è contento è contento ed è l unico contento, bisogna dare 1 in output nessuno è contento, bisogna dare 0 in output se si hanno c1 nodi contenti nel sotto albero sinistro e c2 in quello destro e se il numero dei nodi nel sotto albero sinistro è minore di quello nel sotto albero destro allora bisogna dare in output c1+c2+1, altrimenti c1+c2 Occorre sapere per ogni nodo, sia il numero dei nodi nei sotto alberi e il numero dei nodi contenti nei due sottoalberi. Si può usare una coppia di valori in output. Prof. E. Fachini - Intr. Alg. 3
Numero di nodi contenti, pseudocodicce Si definisca un algoritmo ricorsivo che dà in output il numero di nodi contenti nel'albero di input, se non è vuoto e -1 altrimenti. Un nodo e' contento se nell'albero in esso radicato ci sono piu' nodi figli sinistri che destri. contenti(t) input: il puntatore alla radice di un albero binario output: il numero dei nodi contenti in T (n,c) = contaux(t); return c} Tempo di esecuzione: T(n) = T(k) +T(n-k-1) + Θ(1), nel caso peggiore, dove n è il numero dei nodi di T, quindi O(n) contaux(t) input: il puntatore alla radice di un albero binario e una variabile intera n output: la coppia con il numero dei nodi e il numero dei nodi contenti in T if T è nil return (0,0) if T è una foglia return (1,0) if (T.left nil) then (n1,c1) = contaux(t.left) if (T.right nil) then (n2,c2) = contaux(t.right) if (n1 - n2 > 0) then return (n1+n2+1,c1+c2+1) else return (n1+n2+1,c1+c2) Prof. E. Fachini - Intr. Alg. 4
Verifica completo Si costruisca un algoritmo ricorsivo che verifica se un albero binario t, rappresentato con strutture a puntatori, è completo. l albero è vuoto ed è completo è completo non è completo è completo in generale? Prof. E. Fachini - Intr. Alg. 5
Verifica completo Si costruisca un algoritmo ricorsivo che verifica se un albero binario t, rappresentato con strutture a puntatori, è completo. l albero è vuoto ed è completo è completo non è completo è completo in generale? Se ogni nodo ha lo stesso numero di nodi nel suo sotto albero sinistro e nel destro? Se ogni nodo ha l altezza del suo sotto albero sinistro uguale a quella del destro? Prof. E. Fachini - Intr. Alg. 6
Verifica completo u b d e f a i j m p q r s c g l albero è completo sse tutti e due i suoi sotto alberi hanno la stessa altezza o lo stesso numero di nodi h1 h2 Decidiamo di calcolare l altezza: se h1=h2 restituiamo h1+1 altrimenti? prendiamo -2 che non è un altezza. Prof. E. Fachini - Intr. Alg. 7
Verifica completo, pseudocodice VerCompl(T) input: un albero binario T, rappresentato con strutture a puntatori postc: restituisce l altezza dell albero se l albero è completo, -2 altrimenti. if (T==NIL) return -1 h1 = VerCompl(T.left) h2 = VerCompl(T.right) if (h1 = -2) or ( h2 = -2) then return -2 //almeno uno non è completo else if (h1 = h2) then return h1+1 else return -2 Tempo di esecuzione T(n) = T(k) + T(n-k -1) + Θ(1) in tutti i casi. Quindi Θ(n) Prof. E. Fachini - Intr. Alg. 8
Verifica quasi completo Si costruisca un algoritmo ricorsivo che verifica se un albero binario t, rappresentato con strutture a puntatori, è quasi completo. h= -1 h= 0, i due sottoalberi hanno altezza uguale -1 h= 1, il sinistro ha altezza h1=0 e il destro h2= -1, O.K. h= 1, il sinistro ha altezza h1=0 e il destro h2 = 0, O.K. Prof. E. Fachini - Intr. Alg. 9
Esercizio alberi binari qualunque Dato un albero binario la lunghezza del cammino interno è la somma dei livelli dei suoi nodi interni. Si scriva e si analizzi un algoritmo per il calcolo della lunghezza del cammino interno. Esempio: Per l albero in figura il cammino interno è 0*1 + 2*1 + 1*2 + 1*3 = 7 3 1 5 2 4 7 6 9 8 E. Fachini
Lunghezza cammino interno B A C T1 T2 Bisogna chiedersi di quale valore si deve disporre al rientro dalle chiamate sui due figli A e C per poter concludere il calcolo su B. Se immaginiamo di disporre al rientro su A e C delle lunghezze dei cammini interni dei due sotto alberi, T1 e T2, (con i livelli riferiti a tutto l albero), cosa bisogna avere d altro per calcolare la lunghezza del cammino interno per B? Basta avere il livello di B e sommarlo ai risultati ottenuti dalle chiamate sui figli. Come ottengo il livello? Basta calcolarlo in un parametro, inizializzato a 0 e incrementato ad ogni chiamata, al rientro riprenderà il valore calcolato scendendo su quel nodo e sarà quindi il valore giusto da sommare. Prof. E. Fachini - Intr. Alg. 11
Soluzione esercizio cammino interno algoritmo cammint(t,liv) input: T è il puntatore alla radice di un albero binario e liv è un intero output: la lunghezza del cammino interno di T liv inizialmente vale 0 e contiene il livello di T. if T = NULL then return 0 if T.left = NULL and T.right = NULL then return 0 return cammint(t.left,liv+1) + cammint(t.right,liv+1) + liv E. Fachini 12
Ultima Foglia Dato un albero binario T, quasi completo (cioè completo fino al penultimo livello, con le foglie al più su due livelli e con le foglie sull ultimo livello tutte a sinistra) implementato con strutture a puntatori, si implementi un algoritmo che ricevuto in input T restituisce in output il puntatore all ultima foglia. L algoritmo deve avere una complessita O((lg n) 2 ), se n è il numero degli elementi in T. Si illustri l idea algoritmica prima di passare alla stesura in pseudocodice, in cui prima di tutto si deve indicare l output atteso delle singole funzioni utilizzate, oltre ad eventuali vincoli sull input. Esempio: nel primo albero la risposta è il link al nodo 1, nel secondo al nodo 2 più a destra. 16 16 14 14 8 7 9 3 8 6 9 3 2 4 1 2 4 1 5 7 8 1 2
Casi base: 16 Analisi problema 8 7 2 4 1 Come posso individuare il sotto albero che contiene l ultima foglia? Osserviamo che se la lunghezza del cammino più a sinistra nel sotto albero sinistro e destro sono uguali allora l ultima foglia è nel sotto albero destro, altrimenti nel sinistro. Sia CPS la funzione che restituisce il numero di nodi attraversati lungo un cammino che parte dalla radice e scende lungo legami padre-figlio sinistro fino a che il nodo è privo di figlio sinistro.
Verso la soluzione se CPS(T.left) = CPS(T.right) dirigo la ricerca nel sottoalbero destro CPS(T.left) = CPS(T.right) CPS(T.left) = CPS(T.right) se CPS(T.left) = CPS(T.right) + 1 dirigo la ricerca nel sottoalbero sinistro CPS(T.left) = CPS(T.right) + 1 CPS(T.left) = CPS(T.right) + 1 Tempo di esecuzione di CSP Θ(h) = Θ(lg n)
UltimaFoglia(T) Input: un albero binario T precond: T è quasi completo output: il puntatore all ultima foglia Pseudocodice if (T == NIL o è una foglia) then return T m = CPS(T.left) m = CPS(T.right) if (m == m ) then return UltimaFoglia(T.right) if (m == m + 1) then return UltimaFoglia(T.left) m = m CPS(T) Input: un albero binario T prec. T è non vuoto output: il numero di nodi attraversati lungo un cammino che parte dalla radice e scende lungo legami padre-figlio sinistro fino a che il nodo è privo di figlio sinistro. %Se T un solo nodo dà 1 m = m +1 Tempo di esecuzione T(h) = T(h-1) + Θ(h) in tutti i casi. Quindi Θ(h 2 ) e h = lg n.
ABR è un AVL? Si costruisca e si analizzi un algoritmo che verifica se un dato ABR è bilanciato in altezza. L albero è rappresentato in memoria con strutture e puntatori ai figli. La complessità prevista è O(n), dove n è il numero dei nodi dell albero 17
ABR è un AVL? algoritmo verificaavl(t) input: (il puntatore alla radice di ) un albero binario prec. T è un ABR output: l altezza dell albero se è bilanciato in altezza, -2 altrimenti if T = NULL return -1 h1 = verificaavl(t.left) if h1 = -2 then return -2 * non è bilanciato in altezza* h2 = verificaavl(t.right,) if h2-2 and h1 - h2 1 then return max(h1,h2) +1 else return -2 18
somma dei cammini radice-foglia Si definisca un algoritmo che prende in input un un albero T e un intero k e restituisce vero se c è un cammino radice foglia la cui somma delle chiavi è uguale a k. Si dimostri la correttezza e si analizzi la complessità dell algoritmo proposto.