48
Laboratorio di Algoritmi e Strutture Dati Marco Tarini e-mail: [email protected]

Laboratorio di Algoritmi e Strutture Dati - vcg.isti.cnr.itvcg.isti.cnr.it/~tarini/teaching/alg09/Lezione01.pdf · Robert Sedgewick. Algoritmi in C. Addison-Wesley, Pearson Italia,

Embed Size (px)

Citation preview

Laboratorio di Algoritmi e Strutture Dati

Marco Tarini

e-mail: [email protected]

Argomenti del corso

Calcolo del tempo di computazione di un algoritmo:

I Esercizi di analisi formale: sommatorie, ricorrenze;

I Misurazione sperimentale dei tempi di calcolo;

Implementazione in C di alcuni algoritmi e strutture dati visti alezione:

I Algoritmi di Ricerca e Ordinamento;

I Strutture: liste concatenate, alberi, BST, RB-alberi, Grafi;

I Algoritmi ricorsivi e iterativi;

I Programmazione dinamica.

Variazioni di implementazioni usate frequentemente.

Lezioni frontali e (secondo disponibilita delle aule) in laboratorio.

Modalita d’esame

L’esame e in comune con il Prof. Massazza (15 CFU totali).

Per poter fare l’orale bisogna preparare un progetto in C:

I tre settimane a disposizione;

I si consegna indicativamente 7gg prima dell’orale (la data variaa seconda dell’appello);

I si discute nello stesso giorno dell’orale.

Tutte le informazioni sul sito del corso.

Materiale didattico

Materiale del corso (sul sito, a breve):

I file delle presentazioni;

I codice usato a lezione;

I calendario delle lezioni;

I avvisi di modifiche all’orario;

I avvisi per gli appelli;

I materiale aggiuntivo;

I links utili;

Per informazioni, contattatemi per posta elettronica.

e-mail: [email protected]

Testi di riferimento

Robert Sedgewick.Algoritmi in C.Addison-Wesley, Pearson Italia, 2002.

Brian W. Kernighan, Dennis M. Ritchie.Linguaggio C (seconda edizione),Nuova edizione italiana, Pearson, Italia, 2004.

Al Kelley, Ira Pohl.C Didattica e Programmazione (A book on C, 4th edition).Pearson, Italia, 2004.

Compilatore di riferimento

Useremo il compilatore gcc (GNU Compiler Collection).

Scaricatelo da

I per UNIX:

http://gcc.gnu.org/

I per Windows:

http://www.cs.colorado.edu/~main/cs1300/

Oppure un IDE qualunque

I es, DevCpp

Calcolo delle prestazioni degli algoritmi

Un algoritmo e un insieme di istruzioni finalizzate a risolvere unproblema.

I Ci possono essere piu algoritmi che risolvono lo stessoproblema.

I (ma un algoritmo risolve un solo problema).

Per valutare quale sia migliore si analizzano quante risorseimpegano per resituire una soluzione:

I tempo (di calcolo)

← soprattutto questo

I spazio (di memoria)

I banda (di rete)

I eccetera

Calcolo delle prestazioni degli algoritmi

Un algoritmo e un insieme di istruzioni finalizzate a risolvere unproblema.

I Ci possono essere piu algoritmi che risolvono lo stessoproblema.

I (ma un algoritmo risolve un solo problema).

Per valutare quale sia migliore si analizzano quante risorseimpegano per resituire una soluzione:

I tempo (di calcolo)

← soprattutto questo

I spazio (di memoria)

I banda (di rete)

I eccetera

Calcolo delle prestazioni degli algoritmi

Un algoritmo e un insieme di istruzioni finalizzate a risolvere unproblema.

I Ci possono essere piu algoritmi che risolvono lo stessoproblema.

I (ma un algoritmo risolve un solo problema).

Per valutare quale sia migliore si analizzano quante risorseimpegano per resituire una soluzione:

I tempo (di calcolo) ← soprattutto questo

I spazio (di memoria)

I banda (di rete)

I eccetera

Calcolo delle prestazioni degli algoritmi (cont.)

Il tempo di esecuzione dipende da molti fattori. Lo stessoalgoritmo impiega:

I tempo diverso su input diversi (1);

I tempi diversi sullo stesso input, quando e eseguito sucomputer diversi (2).

(1) Chiediamo che il tempo di esecuzione sia stimato in relazionealla grandezza dell’input.

(2) L’analisi di complessita degli algoritmi cerca di stabilire il tempodi calcolo indipendentemente dalla macchina sulla quale eimplementato il programma.

Calcolo delle prestazioni degli algoritmi (cont.)

Il tempo di esecuzione dipende da molti fattori. Lo stessoalgoritmo impiega:

I tempo diverso su input diversi (1);

I tempi diversi sullo stesso input, quando e eseguito sucomputer diversi (2).

(1) Chiediamo che il tempo di esecuzione sia stimato in relazionealla grandezza dell’input.

(2) L’analisi di complessita degli algoritmi cerca di stabilire il tempodi calcolo indipendentemente dalla macchina sulla quale eimplementato il programma.

Calcolo delle prestazioni degli algoritmi (cont.)

Il tempo di esecuzione dipende da molti fattori. Lo stessoalgoritmo impiega:

I tempo diverso su input diversi (1);

I tempi diversi sullo stesso input, quando e eseguito sucomputer diversi (2).

(1) Chiediamo che il tempo di esecuzione sia stimato in relazionealla grandezza dell’input.

(2) L’analisi di complessita degli algoritmi cerca di stabilire il tempodi calcolo indipendentemente dalla macchina sulla quale eimplementato il programma.

Esempio 1

Supponiamo che la stampa di un numero costi

1 secondo

e consideriamo un programma che legge un numero n e:

Caso A: stampa i numeri da 0 a n − 1.

Caso B: stampa tutte le coppie di numeri da 0 a n − 1.

Caso C: stampa tutte le potenze di 2 piu piccole di n.

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1

1 1 1

2

2 4 2

3

3 9 2

4

4 16 3

5

5 25 3

10

10 100 4

20

20 400 5

50

50 2500 6

100

100 10000 71000 1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1

1 1

2 2

4 2

3 3

9 2

4 4

16 3

5 5

25 3

10 10

100 4

20 20

400 5

50 50

2500 6

100 100

10000 71000 1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1

1

2 2 4

2

3 3 9

2

4 4 16

3

5 5 25

3

10 10 100

4

20 20 400

5

50 50 2500

6

100 100 10000

71000 1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1 12 2 4 23 3 9 24 4 16 35 5 25 3

10 10 100 420 20 400 550 50 2500 6

100 100 10000 7

1000 1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1 12 2 4 23 3 9 24 4 16 35 5 25 3

10 10 100 420 20 400 550 50 2500 6

100 100 10000 71000

1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1 12 2 4 23 3 9 24 4 16 35 5 25 3

10 10 100 420 20 400 550 50 2500 6

100 100 10000 71000 1.000 1.000.000 10

106 106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1 12 2 4 23 3 9 24 4 16 35 5 25 3

10 10 100 420 20 400 550 50 2500 6

100 100 10000 71000 1.000 1.000.000 10106

106 1012 20

Esempio 1 (cont.)Tabella di esecuzione

Al variare di n indichiamo quanti secondi spende ogni algoritmoper la stampa:

n A B C

1 1 1 12 2 4 23 3 9 24 4 16 35 5 25 3

10 10 100 420 20 400 550 50 2500 6

100 100 10000 71000 1.000 1.000.000 10106 106 1012 20

Esempio 1 (cont.)Le differenze tra il costo dei diversi algoritmi sono tanto piugrandi quanto e piu grande l’input.

Caso A se l’input raddoppia di grandezza, il costo raddoppia.

Caso B se l’input raddoppia di grandezza, il costo quadruplica.

Caso C se l’input raddoppia di grandezza, il costo aumenta di 1 sec.25

15

5

04 5321

n

10

20

Velocita di crescita delle funzioni

La complessita di un algoritmo deve quindi essere funzione delladimensione dell’input.

Per valori piccoli degli input, algoritmi con tempi di esecuzionediversi possono impiegare in realta tempi molto simili.

Ma quando gli input hanno dimensione maggiore, allora ladifferenza diventa rilevante.

Pseudo-codice

I Caso A:

for (i=0;i<n;i++)print(i);

I Caso B:

for (i=0;i<n;i++)for (j=0;j<n;j++)

print((i,j));

I Caso C:

for (i=1;i<n;i=2*i)print(i);

Esempio 1 (cont.)Tabella di esecuzione

Che succede se il costo passa da 1 a 50 secondi per operazione?

n A B C

1

50 50 50

2

100 200 100

3

150 450 100

4

200 800 150

5

250 1250 150

10

500 5000 200

50

2500 125000 300

100

5000 5000000 350

Esempio 1 (cont.)Tabella di esecuzione

Che succede se il costo passa da 1 a 50 secondi per operazione?

n A B C

1 50

50 50

2 100

200 100

3 150

450 100

4 200

800 150

5 250

1250 150

10 500

5000 200

50 2500

125000 300

100 5000

5000000 350

Esempio 1 (cont.)Tabella di esecuzione

Che succede se il costo passa da 1 a 50 secondi per operazione?

n A B C

1 50 50

50

2 100 200

100

3 150 450

100

4 200 800

150

5 250 1250

150

10 500 5000

200

50 2500 125000

300

100 5000 5000000

350

Esempio 1 (cont.)Tabella di esecuzione

Che succede se il costo passa da 1 a 50 secondi per operazione?

n A B C

1 50 50 502 100 200 1003 150 450 1004 200 800 1505 250 1250 150

10 500 5000 20050 2500 125000 300

100 5000 5000000 350

Esempio 1 (cont.)

Al crescere dell’input, i comportamenti restano uguali:

Caso A se l’input raddoppia di grandezza, il costo raddoppia.

Caso B se l’input raddoppia di grandezza, il costo quadruplica.

Caso C se l’input raddoppia, il costo aumenta di 50 sec.25

15

5

04 5321

n

10

20

0

n

2 54

1200

800

400

1 3

1000

600

200

Ecco perche...

L’analisi dei costi di un algoritmo:

1. si effettua in funzione della dimensione dell’input:I caso peggiore (su input di dimensione n)I caso ottimo (su input di dimensione n)I caso medio (su input di dimensione n)

I ma: su che distribuzione degli input?;

2. si studia spesso in termini di comportamento asintotico:I le costanti diventano importanti solo in situazioni particolari o

a parita di costo asintotico;I le equazioni che descrivono il costo diventano piu semplici.

Notazioni asintoticheRipasso delle definizioni

Def: siano f e g due funzioni da N in N.

I f (n) = O(g(n)) sse ∃c , n0 ∈ N | ∀n > n0, f (n) < cg(n);

I f (n) = Ω(g(n)) sse ∃c , n0 ∈ N | ∀n > n0, cf (n) > g(n);

I f (n) = Θ(g(n)) sse f (n) = O(g(n)) e f (n) = Ω(g(n)).

Esercizio 1: analisi di complessitaInsertion Sort

void insertionSort( int a[], int length ) int i, j, v;for ( i = 1; i < length; i++ ) j = i - 1;v = a[i];while ( ( j >= 0 ) && ( a[j] > v ) )

a[j+1] = a[j];j--;

a[j+1] = v;

I Caso migliore: Θ(n);

I Caso peggiore: Θ(n2);

I Caso medio: Θ(n2);

Esempio.

La funzione f : n ∈ N 7→ 2n e O(n).Infatti per n > 1 si ha 2n ≤ 3n.

Esercizi:

I 5n2 + n = O(n2) ?

I log2(8n) = O(n) ?

I n2 = O(n) ?

Alcune proprieta

O e Ω sono relazioni opposte.

I se g = O(f ) allora f = Ω(g)

Θ e una relazione di equivalenza!

Per ogni funz f g h da naturali a naturali

I f = Θ(f ) (riflessiva)

I se f = Θ(g) allora g = Θ(f ) (simmetrica)

I se f = Θ(g) e g = Θ(h) allora f = Θ(h) (transitiva)

In quanto tale, Θ divide le funzioni in classi di equivalenza.

Alcune proprieta

O e Ω sono relazioni opposte.

I se g = O(f ) allora f = Ω(g)

Θ e una relazione di equivalenza!

Per ogni funz f g h da naturali a naturali

I f = Θ(f ) (riflessiva)

I se f = Θ(g) allora g = Θ(f ) (simmetrica)

I se f = Θ(g) e g = Θ(h) allora f = Θ(h) (transitiva)

In quanto tale, Θ divide le funzioni in classi di equivalenza.

Alcune proprieta

O e Ω sono relazioni opposte.

I se g = O(f ) allora f = Ω(g)

Θ e una relazione di equivalenza!

Per ogni funz f g h da naturali a naturali

I f = Θ(f ) (riflessiva)

I se f = Θ(g) allora g = Θ(f ) (simmetrica)

I se f = Θ(g) e g = Θ(h) allora f = Θ(h) (transitiva)

In quanto tale, Θ divide le funzioni in classi di equivalenza.

Funzioni di riferimento

Si usano alcune funzioni di riferimento per la notazione asintotica.

I f = Θ(1) : f ha andamento costante

I f = Θ(log(N)) : f ha andamento logaritmico

I f = Θ(N) : f ha andamento lineare

I f = Θ(Nlog(N)) : f ha andamento pseudo-lineare

I f = Θ(N2) : f ha andamento quadratico

I f = Θ(N3) : f ha andamento cubico ...

I f = Θ(NK ) : f ha andamento polinomiale (K costante)

I f = Θ(KN) : f ha andamento esponenziale (K costante)

Sono classi di equivalenza per Θ! (una per ogni K ).

A parole

Per N abbastanza grandi, e a meno di una costantemoltiplicativia...f = O(g) significa “f vale meno di g”f = Ω(g) significa “f vale piu di g”f = Θ(g) significa “f e g si comportano allo stesso modo”

f = O(N2) significa “f ha andamento al piu quadratico”.f = Ω(N2) significa “f ha andamento almeno quadratico”.f = Θ(N2) significa “f ha andamento quadratico”.

Esercizio 2: AlberiQuanti nodi ha un albero k-ario completo di altezza h?

I il livello 0 contiene 1 nodo (la radice);

I il livello 1 contiene k nodi;

I il livello 2 contiene k2 nodi;

I il livello i contiene k i nodi;

1 + k + k2 + · · ·+ k(h−1) =h−1∑i=0

k i =kh − 1

k − 1

Esercizio 2: AlberiQuanti nodi ha un albero k-ario completo di altezza h?

I il livello 0 contiene 1 nodo (la radice);

I il livello 1 contiene k nodi;

I il livello 2 contiene k2 nodi;

I il livello i contiene k i nodi;

1 + k + k2 + · · ·+ k(h−1) =h−1∑i=0

k i =kh − 1

k − 1

Esercizio 2: AlberiQuanti nodi ha un albero k-ario completo di altezza h?

I il livello 0 contiene 1 nodo (la radice);

I il livello 1 contiene k nodi;

I il livello 2 contiene k2 nodi;

I il livello i contiene k i nodi;

1 + k + k2 + · · ·+ k(h−1) =h−1∑i=0

k i =kh − 1

k − 1

Esercizio 2: Alberi (cont.)

Quanti cammini diversi partono dalla radice?

I Esiste uno ed un solo cammino dalla radice ad ogni nodo:

kh − 1

k − 1− 1

E quant’e la lunghezza totale di questi cammini?

I (per i nodi a livello 1) ho k cammini di lunghezza 1;

I (per i nodi a livello 2) ho k2 cammini di lunghezza 2;

I (per i nodi a livello i) ho k i cammini di lunghezza i ;

k + 2k2 + · · ·+ (h − 1)kh−1 =h−1∑i=0

ik i

= k(h − 1)kh − hkh−1 + 1

(k − 1)2

Esercizio 2: Alberi (cont.)

Quanti cammini diversi partono dalla radice?

I Esiste uno ed un solo cammino dalla radice ad ogni nodo:

kh − 1

k − 1− 1

E quant’e la lunghezza totale di questi cammini?

I (per i nodi a livello 1) ho k cammini di lunghezza 1;

I (per i nodi a livello 2) ho k2 cammini di lunghezza 2;

I (per i nodi a livello i) ho k i cammini di lunghezza i ;

k + 2k2 + · · ·+ (h − 1)kh−1 =h−1∑i=0

ik i = k(h − 1)kh − hkh−1 + 1

(k − 1)2

Esercizio 2: Alberi (cont.)

Quanti cammini diversi partono dalla radice?

I Esiste uno ed un solo cammino dalla radice ad ogni nodo:

kh − 1

k − 1− 1

E quant’e la lunghezza totale di questi cammini?

I (per i nodi a livello 1) ho k cammini di lunghezza 1;

I (per i nodi a livello 2) ho k2 cammini di lunghezza 2;

I (per i nodi a livello i) ho k i cammini di lunghezza i ;

k + 2k2 + · · ·+ (h − 1)kh−1 =h−1∑i=0

ik i = k(h − 1)kh − hkh−1 + 1

(k − 1)2

Esercizio 2: Alberi (cont.)

Quanti cammini diversi partono dalla radice?

I Esiste uno ed un solo cammino dalla radice ad ogni nodo:

kh − 1

k − 1− 1

E quant’e la lunghezza totale di questi cammini?

I (per i nodi a livello 1) ho k cammini di lunghezza 1;

I (per i nodi a livello 2) ho k2 cammini di lunghezza 2;

I (per i nodi a livello i) ho k i cammini di lunghezza i ;

k + 2k2 + · · ·+ (h − 1)kh−1 =h−1∑i=0

ik i = k(h − 1)kh − hkh−1 + 1

(k − 1)2

Tipico problemino

Problema della ricerca su vettore ordinato.“Dato un vettore ordinato a di valori e un valore v , capire se v epresente in a e, se se lo e, a quale posizione.”Vediamo due possibili algoritmi per questo problema.Algoritmo 1: Ricerca lineare (o esaustiva)Algoritmo 2: Ricerca binaria

Ricerca lineare

Implementazione:

int linearSearch( int a[], int length, int v ) int i;for (i=0; i<length; i++) if ( a[i] == v) return i; /* trovato! */

return -1; /* non l’ho trovato */

Complessita? Caso ottimo?

Caso pessimo?E il caso medio?

Ricerca binaria

int binarySearch( int a[], int length, int v ) int m, r = length - 1, l = 0;while( r >= l ) m = ( l + r ) / 2;if ( v == a[m] ) return m;if ( v < a[m] ) r = m - 1;

else l = m + 1;return -1;

Complessita? Ogni test esclude meta dell’array:

T (n) ≤ T (bn/2c) + 1 (considero solo i confronti).

T (n) ≤ log2 n + 1

E il caso medio?