Esercizi di Algoritmi e Strutture Dati

Documenti analoghi
Esercizi di Algoritmi e Strutture Dati

Esercizi di Algoritmi e Strutture Dati

Problemi, istanze, soluzioni

Esercizi Capitolo 6 - Alberi binari di ricerca

Fondamenti di Informatica. Algoritmi di Ricerca e di Ordinamento

PROGRAMMAZIONE STRUTTURATA

2.3 Cammini ottimi. E. Amaldi Fondamenti di R.O. Politecnico di Milano 1

Alberi binari di ricerca

Analisi ammortizzata (Tarjan in 1985)

Algoritmo basato su cancellazione di cicli

Array e liste. IASD a.a

Algoritmi e Strutture Dati. HeapSort

Esercizi Capitolo 6 - Alberi binari di ricerca

Dati e Algoritmi I (Pietracaprina) Esercizi sugli Alberi

Introduzione agli Algoritmi ed alle Strutture Dati Anno Accademico 2015/2016 Appello 23/6/2016

Alberi Binari di Ricerca

Heap e code di priorità

11.4 Chiusura transitiva

Algoritmi e soluzione di problemi

Algoritmi e Strutture Dati - Prof. Roberto De Prisco A.A Seconda prova di verifica (4 Febbraio 2005)

Esercizi proposti 10

Ordinamenti per confronto: albero di decisione

ADT Coda con priorità

Teoria dei Giochi Prova del 30 Novembre 2012

4.5 Metodo del simplesso

Esercitazione. Ricorsione. May 31, Esercizi presi dal libro di Rosen

UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA. Matlab: esempi ed esercizi

Derivazione numerica. Introduzione al calcolo numerico. Derivazione numerica (II) Derivazione numerica (III)

Esercitazione 3. Espressioni booleane I comandi if-else e while

in termini informali: un algoritmo è una sequenza ordinata di operazioni che risolve un problema specifico

Introduzione al Metodo del Simplesso. 1 Soluzioni di base e problemi in forma standard

Progettazione di algoritmi

Appunti di informatica. Lezione 10 anno accademico Mario Verdicchio

PROGRAMMAZIONE: Le strutture di controllo

Esercitazione 6. Array

Esercizi Capitolo 5 - Alberi

n deve essere maggiore di 0, altrimenti il metodo restituisce null.

Algoritmi e Strutture Dati

Esercizi Capitolo 7 - Hash

6) Descrivere con un diagramma a blocchi un algoritmo che legga da input due numeri ne calcoli il prodotto in termini di somme ripetute.

Corso di Calcolo Numerico

Corso di Fondamenti di Informatica

Esempio : i numeri di Fibonacci

Unità Didattica 2 Linguaggio C. Espressioni, Operatori e Strutture linguistiche per il controllo del flusso

Esercizio. Sia a R non nullo e siano m, n numeri interi non nulli con m n. Allora a m /a n è uguale a. [1] 1/a n m [2] 1/a m n [3] 1/a n m [4] a n m

Corso di Algoritmi e Strutture Dati Informatica per il Management Prova Scritta, 15/9/2016

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1

Algoritmi e Strutture Dati

Sistemi lineari. Lorenzo Pareschi. Dipartimento di Matematica & Facoltá di Architettura Universitá di Ferrara

Introduzione alla programmazione Algoritmi e diagrammi di flusso. Sviluppo del software

Strutture di controllo in C++

Argomenti della lezione. Criteri di divisibilità fattorizzazione m.c.m. e M.C.D. frazioni ed espressioni

Fondamenti di Informatica 1. Prof. B.Buttarazzi A.A. 2010/2011

Esercizi di Algoritmi e Strutture Dati

Grafi pesati Minimo albero ricoprente

Esercitazione 6. Alberi binari di ricerca

Analisi asintotica della complessità di tempo degli algoritmi

2. Algoritmi e Programmi

Riassumiamo le proprietà dei numeri reali da noi utilizzate nel corso di Geometria.

Array in Fortran 90. Ing. Luca De Santis. Anno accademico 2006/2007. DIS - Dipartimento di informatica e sistemistica

Lezione 9 Alberi binari di ricerca

Grafi: visita generica

Sviluppo di programmi. E ora, finalmente. Si comincia! 1. Analizzare il problema. 2. Progettare una soluzione (1) E necessario capire:

La codifica digitale

Algoritmi e Strutture Dati & Laboratorio di Algoritmi e Programmazione

Alberi binari e alberi binari di ricerca

alberi tipo astratto, implementazione, algoritmi

Programmazione Funzionale

Bontà dei dati in ingresso

I. Foglio di esercizi su vettori linearmente dipendenti e linearmente indipendenti. , v 2 = α v 1 + β v 2 + γ v 3. α v 1 + β v 2 + γ v 3 = 0. + γ.

In molte applicazioni sorge il problema di sapere in quanti modi possibili si può presentare un certo fenomeno.

Teoria dei Giochi Prova del 9 Settembre se tutti i giocatori scelgono lo stesso numero, il payoff è zero per ciascun giocatore;

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

Laboratorio di Algoritmi e Strutture Dati. Aniello Murano. people.na.infn.it/~murano/ Murano Aniello - Lab. di ASD Terza Lezione

Compitino di Laboratorio di Informatica CdL in Matematica 13/11/2007 Teoria Compito A

Sistemi di equazioni lineari

Strutture dati e loro organizzazione. Gabriella Trucco

Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE. Francesco Tura. F. Tura

ECONOMIA APPLICATA ALL INGEGNERIA (Docente: Prof. Ing. Donato Morea)

Linguaggi e Grammatiche Liberi da Contesto

Prontuario degli argomenti di Algebra

I RADICALI QUADRATICI

TRIE (albero digitale di ricerca)

Parte 2. Ricorsione. [M.C.Escher Drawing hands, 1948] - AA. 2012/13 2.1

Algoritmi e Principi dell Informatica

Diagrammi a blocchi 1

Esercizi su Python. 14 maggio Scrivere una procedura che generi una stringa di 100 interi casuali tra 1 e 1000 e che:

Spiegazioni ASD 2012 Luddisti Spaziali

Algoritmi e Strutture di Dati I 1. Algoritmi e Strutture di Dati I Massimo Franceschet francesc

I B+ Alberi. Sommario

Problema dell albero di cammini minimi (SPT, Shortest Path Tree) o problema dei cammini minimi :

Laboratorio di programmazione

Programmazione I. 11 gennaio Considerate la seguente gerarchia di classi (rappresentata mediante un diagramma UML): +f(double x):

Corso di Fondamenti di Informatica. La ricorsione

Vettori e matrici. Lorenzo Pareschi. Dipartimento di Matematica & Facoltá di Architettura Universitá di Ferrara

LA TRASMISSIONE DELLE INFORMAZIONI SECONDA PARTE 1

Teorema di Thevenin generalizzato

Laboratorio di Programmazione Appunti sulla lezione 4: Divide et impera e algoritmi di ordinamento

La principale modalità di calcolo è l applicazione di funzioni

Esercitazione 4. Comandi iterativi for, while, do-while

Transcript:

Esercizi di Algoritmi e Strutture Dati Moreno Marzolla marzolla@cs.unibo.it Ultimo aggiornamento: 3 novembre 2010 1 Trova la somma/1 Scrivere un algoritmo che dati in input un array A[1... n] di n interi positivi (ossia tutti strettamente maggiori di zero) e un intero positivo v, restituisce true se e solo se esistono due valori in A la cui somma sia esattamente uguale a v. Analizzare il costo computazionale dell algoritmo proposto. Soluzione L algoritmo controlla tutte le coppie A[i], A[j], con 1 i < j n per verificare se A[i] + A[j] = v per qualche valore di i e j. Lo pseudocodice è il seguente: algoritmo trova_somma(array A[1..n] di interi, intero v) -> bool for i:=1 to n-1 do for j:=i+1 to n do if (A[i] + A[j] == v) then return true; return false; Analizziamo il costo computazionale dell algoritmo proposto. Il corpo del ciclo for più interno ha costo O(1), e viene eseguito n i volte, per i = 1, 2,... n 1. Pertanto, il costo complessivo si ottiene come: n 1 n 1 (n i) = i = i=1 i=1 n(n 1) 2 Da cui il costo complessivo dell algoritmo nel caso generale è O(n 2 ) (non Θ(n 2 ), perché l algoritmo potrebbe terminare in qualsiasi momento se l if risulta vero). Il caso peggiore si ha quando non esiste alcuna coppia di indici i < j per cui A[i] + A[j] = v, e in tal caso il costo dell algoritmo è Θ(n 2 ). Il caso migliore si verifica quando A[1] + A[2] = v, e in tal caso il costo dell algoritmo è O(1) in quanto l algoritmo termina alla prima iterazione. 1

2 Trova la somma/2 Scrivere un algoritmo che dati in input un array A[1... n] di n interi positivi (ossia tutti strettamente maggiori di zero), restituisce true se e solo se esistono due valori in A la cui somma sia esattamente uguale a 17. L algoritmo deve avere costo O(n). (Suggerimento: utilizzare un vettore di valori booleani B[1... 16] tale che...). Soluzione L idea è la seguente: tutti gli elementi del vettore B sono inizialmente settato a false. Si effettua quindi una scansione lineare dell array A. Per ogni intero k presente in A tale che 1 k 16, si pone B[k] = true. Al termine si effettua una scansione di B, controllando se esiste un indice i per cui B[i] = B[17 i] = true. In caso affermativo l algoritmo ritorna true (esistono due numeri in A la cui somma è 17, e tali numeri sono i e 17 i), altrimenti ritorna false. Lo pseudocodice è il seguente: algoritmo esiste_coppia_17( array A[1..n] di interi ) -> bool Sia B[1..16] un array di bool // blocco (1) for i:=1 to 16 do B[i] := false; // blocco (2) for i:=1 to n do if ( A[i] < 17 ) then B[A[i]] := true; // blocco (3) for i:=1 to 8 do if (B[i] == true && B[17-i] == true) return true; return false; Analizziamo il costo computazionale dell algoritmo proposto. Il ciclo for indicato con blocco (1) ha costo O(1): si noti infatti che effettua un numero costante di iterazioni, e ogni iterazione ha costo O(1). Il ciclo indicato con blocco (2) ha costo Θ(n). Infine, il ciclo indicato con blocco (3) ha costo O(1) percé anche qui viene eseguito al più 8 volte, e ogni iterazione costa O(1). Notiamo che se dobbiamo cercare una coppia di valori la cui somma sia 16 (oppure un qualsiasi numero pari) la soluzione sopra non funziona: questo si 2

puo verificare applicando l algoritmo al vettore A = [8, 5]. Il problema è che in questo caso non è sufficiente sapere se un certo valore compare in A, ma anche quante volte compare. La soluzione corretta è la seguente: algoritmo esiste_coppia_16( array A[1..n] di interi ) -> bool Sia B[1..15] un array di interi // blocco (1) for i:=1 to 15 do B[i] := 0; // blocco (2) for i:=1 to n do if ( A[i] < 16 ) then B[A[i]] := B[A[i]]+1; // blocco (3) for i:=1 to 8 do if ( (i==8 && B[i]>1) (B[i]>0 && B[16-i]>0) ) then return true; return false; che ha sempre costo O(n). 3 Profondità di un albero binario Dato un albero binario T, scrivere un algoritmo che calcola la profondità di T. Analizzare il costo computazionale dell algoritmo proposto. Quando si verifica il caso ottimo? Quando si verifica il caso pessimo? Soluzione Una possibile soluzione è la seguente: algoritmo profondita(albero binario T) -> intero if ( T == null ) then errore: albero vuoto! int p_left := 0; if ( T.left()!= null ) then p_left := 1+profondita(T.left()); int p_right := 0; 3

if ( T.right()!= null ) then p_right := 1+profondita(T.right()); return max(p_left, p_right); ove la funzione max(a,b) restituisce il massimo valore tra a e b. Il costo dell algoritmo è Θ(n) (infatti sia nel caso ottimo che nel caso pessimo visita tutti i nodi dell albero una e una sola volta). L analisi può essere fatta risolvendo l equazione di ricorrenza per il tempo T (n), che ha la stessa forma di quella degli algoritmi di visita analizzati a lezione. 4 Conta foglie Dato un albero binario T, scrivere un algoritmo che calcola il numero di foglie di T (le foglie sono i nodi che non hanno figli). Analizzare il costo computazionale dell algoritmo proposto. Quando si verifica il caso ottimo? Quando si verifica il caso pessimo? Soluzione Una possibile soluzione è la seguente: algoritmo contafoglie(albero binario T) -> intero if ( T == null ) then return 0; if ( T.left() == null && T.right() == null ) then return 1; // il nodo T e una foglia return contafoglie(t.left()) + contafoglie(t.right()); Il costo dell algoritmo è Θ(n) (sia nel caso ottimo che nel caso pessimo visita tutti i nodi dell albero una e una sola volta). L analisi è identica a quella degli algoritmi di visita vista a lezione. 5 Conta nodi Dato un albero binario T e un intero non negativo k, scrivere un algoritmo che calcola il numero di nodi che si trovano esattamente a profondità k (ricordiamo che la radice si trova a profondità zero). Analizzare il costo computazionale dell algoritmo proposto. Quando si verifica il caso ottimo? Quando si verifica il caso pessimo? 4

Soluzione Una possibile soluzione è la seguente: algoritmo contanodi(albero binario T, int k) -> intero if ( T == null ) then return 0; if (k == 0) then return 1; return contanodi(t.left(),k-1) + contanodi(t.right(),k-1); Osserviamo che in questo caso il costo computazionale dell algoritmo dipende dalla profonditá h dell albero e dal valore di k. Infatti l algoritmo opera una visita dell albero fermandosi al livello k. Se k h, significa che ci possono essere dei nodi a livello maggiore di k che non vengono mai esplorati. Il caso migliore si verifica quando ci sono k + 1 nodi fino al livello k (disposti secondo una catena), e il costo dell algoritmo è quindi Θ(k). Il caso peggiore invece si verifica quando l albero binario è completo fino a livello k, il che significa che tutti i nodi fino al livello k (escluso) hanno esattamente due figli. Considerando che un albero binario completo di altezza k ha 2 k+1 1 nodi, il costo nel caso peggiore è O(2 k+1 1) = O(2 k ). se k > h, l algoritmo visita tutti gli n nodi dell albero e il costo è Θ(n) (quindi se k > h, caso ottimo e caso pessimo coincidono). 6 Estensione di array dinamici Supponiamo che uno stack venga implementato mediante un array dinamico S, nel modo seguente: Inizialmente l array S ha dimensione 0; Se vogliamo inserire un nuovo elemento (tramite una operazione push()) in uno stack che già contiene n elementi, e l array è pieno (S.length = n), allora viene allocato un nuovo array di n + d elementi; Se vogliamo rimuovere un elemento (tramite una operazione pop()) da uno stack che ne contiene n, e otteniamo uno stack con n 1 elementi tale che n 1 = S.length d, allora viene allocato un nuovo array avente n 1 elementi. Il costo delle riallocazioni è dato anche qui dal costo di copiare gli elementi dal vecchio al nuovo array. In sostanza, la dimensione anziché raddoppiare o dimezzarsi, cresce o cala di una quantità d costante. 5

1. Partendo da uno stack vuoto, quale è il costo complessivo di una sequenza di n operazioni push()? 2. Partendo da uno stack con n elementi, quale è il costo complessivo di una sequenza di n operazioni pop()? Soluzione L analisi è la stessa che abbiamo visto a lezione nel caso dell algoritmo convenzionale di raddoppiamento-dimezzamento. Supponiamo di inserire n elementi nello stack, a partire dallo stack vuoto. La prima espansione del vettore costa d (vengono copiati d elementi dal vecchio al nuovo vettore). La seconda espansione costa 2d, la terza 3d e così via. Il costo complessivo è quindi: d + 2d + 3d +... + i timesd Le espansioni terminano in corrispondenza dell ultimo indice i per cui risulta id n, ossia i n/d. Il costo complessivo è quindi che è Θ(n 2 ). n/d i=1 ( n n d d i d = d + 1) = 1 ( ) n 2 2 2 d + n 6