24
Fondamenti di Informatica 1 Settimana 4 Marcello Dalpasso 1 1 Ricorsione 2 Il calcolo del fattoriale La funzione fattoriale, molto usata nel calcolo combinatorio, è così definita dove n è un numero intero non negativo 0 se 0 se )! 1 ( 1 ! > = = n n n n n 3 Il calcolo del fattoriale Vediamo di capire cosa significa… 0! = 1 1! = 1(1-1)! = 1· 0! = 1· 1 = 1 2! = 2(2-1)! = 2· 1! = 2· 1 = 2 3! = 3(3-1)! = 3·2! = 3·2·1 = 6 4! = 4(4-1)! = 4·3! = 4·3·2·1 = 24 5! = 5(5-1)! = 5·4! = 5·4·3·2·1 = 120 Quindi, per ogni n intero positivo, il fattoriale di n è il prodotto dei primi n numeri interi positivi 4 Il calcolo del fattoriale Scriviamo un metodo statico per calcolare il fattoriale public static int factorial(int n) { if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else { int p = 1; for (int i = 2; i <= n; i++) p = p * i; return p; } } 5 Il calcolo del fattoriale Fin qui, nulla di nuovo… però abbiamo dovuto fare un’analisi matematica della definizione per scrivere l’algoritmo Realizzando direttamente la definizione, sarebbe stato più naturale scrivere public static int factorial(int n) { if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else return n * factorial(n - 1); } 6 Il calcolo del fattoriale Si potrebbe pensare: “Non è possibile invocare un metodo mentre si esegue il metodo stesso!” Invece, come è facile verificare scrivendo un programma che usi factorial, questo è lecito in Java, così come è lecito in quasi tutti i linguaggi di programmazione public static int factorial(int n) { if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else return n * factorial(n - 1); }

Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Embed Size (px)

Citation preview

Page 1: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 1

1

Ricorsione

2

Il calcolo del fattoriale✔La funzione fattoriale, molto usata nel

calcolo combinatorio, è così definita

dove n è un numero intero non negativo

0 se 0 se

)!1(1

!>=

−=

nn

nnn

3

Il calcolo del fattoriale✔Vediamo di capire cosa significa…

0! = 1 1! = 1(1-1)! = 1·0! = 1·1 = 1 2! = 2(2-1)! = 2·1! = 2·1 = 2 3! = 3(3-1)! = 3·2! = 3·2·1 = 6 4! = 4(4-1)! = 4·3! = 4·3·2·1 = 24 5! = 5(5-1)! = 5·4! = 5·4·3·2·1 = 120

✔ Quindi, per ogni n intero positivo, il fattoriale di nè il prodotto dei primi n numeri interi positivi

4

Il calcolo del fattoriale✔ Scriviamo un metodo statico per calcolare il

fattorialepublic static int factorial(int n){ if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else { int p = 1; for (int i = 2; i <= n; i++) p = p * i; return p; }}

5

Il calcolo del fattoriale✔ Fin qui, nulla di nuovo… però abbiamo dovuto

fare un’analisi matematica della definizione perscrivere l’algoritmo

✔ Realizzando direttamente la definizione, sarebbestato più naturale scriverepublic static int factorial(int n){ if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else return n * factorial(n - 1);}

6

Il calcolo del fattoriale

✔ Si potrebbe pensare: “Non è possibile invocare unmetodo mentre si esegue il metodo stesso!”

✔ Invece, come è facile verificare scrivendo unprogramma che usi factorial, questo è lecito inJava, così come è lecito in quasi tutti i linguaggi diprogrammazione

public static int factorial(int n){ if (n < 0) throw new IllegalArgumentException(); else if (n == 0) return 1; else return n * factorial(n - 1);}

Page 2: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 2

7

La ricorsione✔ Invocare un metodo mentre si esegue lo stesso

metodo è un paradigma di programmazione che sichiama ricorsione

e un metodo che ne faccia uso si chiama metodo ricorsivo

✔ La ricorsione è uno strumento molto potente perrealizzare alcuni algoritmi, ma è anche fonte dimolti errori di difficile diagnosi

8

La ricorsione✔ Per capire come utilizzare correttamente la

ricorsione, vediamo innanzitutto come funziona✔ Quando un metodo ricorsivo invoca se stesso, la

macchina virtuale Java esegue le stesse azioniche vengono eseguite quando viene invocato unmetodo qualsiasi– sospende l’esecuzione del metodo invocante– esegue il metodo invocato fino alla sua

terminazione– riprende l’esecuzione del metodo invocante dal

punto in cui era stata sospesa

9

La ricorsione✔ Vediamo la sequenza usata per calcolare 3!

si invoca factorial(3) factorial(3) invoca factorial(2)

factorial(2) invoca factorial(1) factorial(1) invoca factorial(0)

factorial(0) restituisce 1 factorial(1) restituisce 1

factorial(2) restituisce 2 factorial(3) restituisce 6

✔ Si crea quindi una lista di metodi “in attesa”, chesi allunga e che poi si accorcia fino ad estinguersi

10

La ricorsione✔ In ogni caso, anche se il meccanismo di

funzionamento della ricorsione può sembrarecomplesso, la chiave per un suo utilizzo proficuo è– dimenticarsi come funziona la ricorsione, ma

sapere come vanno scritti i metodi ricorsiviperché il tutto funzioni!

✔ Esistono infatti due regole ben definite che vannoutilizzate per scrivere metodi ricorsivi chefunzionino

11

La ricorsione: caso base✔ Prima regola

– il metodo ricorsivo deve fornire la soluzione delproblema in almeno un caso particolare, senzaricorrere ad una chiamata ricorsiva

– tale caso si chiama caso base della ricorsione– nel nostro esempio, il caso base era

– a volte ci sono più casi base, non è necessario che siaunico

if (n == 0) return 1;

12

La ricorsione: passo ricorsivo✔ Seconda regola

– il metodo ricorsivo deve effettuare la chiamataricorsiva dopo aver semplificato il problema

– nel nostro esempio, per il calcolo del fattoriale di n siinvoca la funzione ricorsivamente per conoscere ilfattoriale di n-1, cioè per risolvere un problema piùsemplice

– il concetto di “problema più semplice” varia di volta involta: in generale, bisogna avvicinarsi ad un caso base

if (n > 0) return n * factorial(n - 1);

Page 3: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 3

13

La ricorsione: un algoritmo?✔Le regole appena viste sono fondamentali

per poter dimostrare che la soluzionericorsiva di un problema sia un algoritmo– in particolare, che arrivi a conclusione in un

numero finito di passi✔Si potrebbe pensare che le chiamate

ricorsive si possano succedere una dopol’altra, all’infinito

14

La ricorsione: un algoritmo?✔Invece, se

– ad ogni invocazione il problema diventa semprepiù semplice e si avvicina al caso base

– la soluzione del caso base non richiedericorsione

allora certamente la soluzione vienecalcolata in un numero finito di passi, perquanto complesso possa essere il problema

15

Ricorsione infinita✔ Abbiamo visto che non tutti i metodi ricorsivi

realizzano algoritmi– se manca il caso base, il metodo ricorsivo continua ad

invocare se stesso all’infinito– se il problema non viene semplificato ad ogni

invocazione ricorsiva, il metodo ricorsivo continua adinvocare se stesso all’infinito

✔ Dato che la lista dei metodi “in attesa” si allungaindefinitamente, l’ambiente runtime esaurisce lamemoria disponibile per tenere traccia di questalista, ed il programma termina con un errore

16

Ricorsione infinita✔ Provare ad eseguire un programma che presenta

ricorsione infinita

✔ Il programma terminerà con la segnalazionedell’eccezione StackOverflowError– il runtime stack è la struttura dati all’interno

dell’interprete Java che gestisce le invocazioni in attesa– overflow significa trabocco

public class InfiniteRecursion{ public static void main(String[] args) { main(args); }}

17

Intervallo

���������������������

������������

18

La ricorsione in coda✔Esistono diversi tipi di ricorsione✔Il modo visto fino ad ora si chiama

ricorsione in coda (tail recursion)– il metodo ricorsivo esegue una sola

invocazione ricorsiva e tale invocazione èl’ultima azione del metodo

public void tail(...){ ... tail(...);}

Page 4: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 4

19

Eliminazione della ricorsione in coda✔La ricorsione in coda può sempre essere

agevolmente eliminata, trasformando ilmetodo ricorsivo in un metodo che usa unciclo public int factorial(int n)

{ if (n == 0) return 1; else return n * factorial(n - 1);}

public int factorial(int n){ int f = 1; while (n > 0) { f = f * n; n--; } return f;}

20

La ricorsione in coda✔Allora, a cosa serve la ricorsione in coda?✔Non è necessaria, però in alcuni casi rende

il codice più leggibile✔È utile quando la soluzione del problema è

esplicitamente ricorsiva (es. fattoriale)✔In ogni caso, la ricorsione in coda è meno

efficiente del ciclo equivalente, perché ilsistema deve gestire le invocazioni sospese

21

La ricorsione non in coda✔Se la ricorsione non è in coda, non è facile

eliminarla (cioè scrivere codice nonricorsivo equivalente), però si puòdimostrare che ciò è sempre possibile– deve essere così, perché il processore esegue

istruzioni in sequenza e non può tenereistruzioni in attesa… quindi l’interprete devefarsi carico di eliminare la ricorsione (usando ilruntime stack)

22

La ricorsione multipla✔Si parla di ricorsione multipla quando un

metodo invoca se stesso più volte duranteuna sua esecuzione– la ricorsione multipla è ancora più difficile da

eliminare, ma è sempre possibile✔Esempio: il calcolo dei numeri di Fibonacci

2 se 20 se

)1Fib()2Fib()Fib(

≥<≤

−+−=

nn

nnn

n

23

I numeri di Fibonacci

✔Il metodo fib realizza una ricorsionemultipla

public static int fib(int n){ if (n < 0) throw new IllegalArgumentException(); else if (n < 2) return n; else return fib(n-2) + fib(n-1);}

24

La ricorsione multipla✔La ricorsione multipla va usata con molta

attenzione, perché può portare a programmimolto inefficienti

✔Eseguendo il calcolo dei numeri diFibonacci di ordine crescente...– … si nota che il tempo di elaborazione cresce

MOLTO rapidamente… quasi 3 milioni diinvocazioni per calcolare Fib(31) !!!!

– più avanti quantificheremo questo problema

Page 5: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 5

25

Progetto: Torri di Hanoi

26

Torri di Hanoi: regole✔ Il rompicapo è costituito da tre pile di dischi (“torri”)

allineate– all’inizio tutti i dischi si trovano sulla pila di sinistra– alla fine tutti i dischi si devono trovare sulla pila di destra

✔ I dischi sono tutti di dimensioni diverse e quando sitrovano su una pila devono rispettare la seguenteregola– nessun disco può avere sopra di sé dischi più grandi

27

Torri di Hanoi: regole Situazione iniziale Situazione finale

28

Torri di Hanoi: regole✔ Per risolvere il rompicapo bisogna spostare un

disco alla volta– un disco può essere rimosso dalla cima della

torre ed inserito in cima ad un’altra torre• non può essere “parcheggiato” all’esterno…

– in ogni momento deve essere rispettata laregola vista in precedenza• nessun disco può avere sopra di sé dischi

più grandi

29

Algoritmo di soluzione✔ Per il rompicapo delle Torri di Hanoi è noto un

algoritmo di soluzione ricorsivo✔ Il problema generale consiste nello spostare n

dischi da una torra ad un’altra, usando la terzatorre come deposito temporaneo

✔ Per spostare n dischi da una torre all’altra sisuppone di saper spostare n-1 dischi da una torreall’altra, come sempre si fa nella ricorsione

✔ Per descrivere l’algoritmo identifichiamo le torricon i numeri interi 1, 2 e 3

30

Algoritmo ricorsivo✔ Per spostare n dischi dalla torre 1 alla torre 3

1 gli n-1 dischi in cima alla torre 1 vengono spostati sullatorre 2, usando la torre 3 come deposito temporaneo (siusa una chiamata ricorsiva, al termine della quale latorre 3 rimane vuota)

2 il disco rimasto nella torre 1 viene portato nella torre 33 gli n-1 dischi in cima alla torre 2 vengono spostati sulla

torre 3, usando la torre 1 come deposito temporaneo (siusa una chiamata ricorsiva, al termine della quale latorre 1 rimane vuota)

✔ Il caso base si ha quando n vale 1 e l’algoritmousa il solo passo 2, che non ha chiamate ricorsive

Page 6: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 6

31

Algoritmo ricorsivo✔Si può dimostrare che il numero di mosse

necessarie per risolvere il rompicapo conl’algoritmo proposto è

12 −n

32

public class Hanoi{ public static void main(String[] v) { solveHanoi(1,3,2,Integer.parseInt(v[0])); } public static void solveHanoi( int from, int to, int temp, int dim) { if (dim > 0) { solveHanoi(from, temp, to, dim-1); System.out.println( "Sposta da " + from + " a " + to); solveHanoi(temp, to, from, dim-1); } }}

Soluzione delle Torri di Hanoi

33

Quando finirà il mondo?

34

Torri di Hanoi: la leggenda✔ Una leggenda narra che alcuni monaci buddisti in un

tempio dell’Estremo Oriente siano da sempre impegnatinella soluzione del rompicapo, spostando fisicamente i loro64 dischi da una torre all’altra, consapevoli che quandoavranno terminato il mondo finirà

✔ Sono necessarie mosse, che sono circa 16 miliardidi miliardi di mosse… cioè circa

✔ Supponendo che i monaci facciamo una mossa ogniminuto, essi fanno circa 500000 mosse all’anno, quindi ilmondo finirà tra circa 30 mila miliardi di anni…

✔ Un processore ad 1GHz che fa una mossa ad ogniintervallo di clock (un miliardo di mosse al secondo…)impiega 16 miliardi di secondi, che sono circa 500 anni...

1264 −18106.1 ×

35

���������������������

��������������������������������

36

✔Riprendiamo un problema già visto

✔ Il ciclo usa la variabile “ausiliaria” done, diversadalla variabile che contiene i dati, line, perché laverifica della condizione va fatta a metà del ciclo

Leggere una sequenza di dati

boolean done = false;while (!done){ String line = console.readLine(); if (line == null) done = true; else ... // elabora line}

Page 7: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 7

37

Il problema del “ciclo e mezzo”✔ Un ciclo del tipo

– “fai qualcosa, verifica una condizione, fai qualcos’altroe ripeti il ciclo se la condizione era vera”

non ha una struttura di controllo predefinita inJava e deve essere realizzata con un “trucco”,come quello, appena visto, di usare una variabilebooleana, detta variabile di controllo del ciclo

✔ Una struttura di questo tipo si chiama anche “cicloe mezzo” o ciclo ridondante (perché c’è qualcosadi “aggiunto”, di innaturale…)

38

Il problema del “ciclo e mezzo”✔ Per uscire da un ciclo si può usare anche

l’enunciato break while (true){ String line = console.readLine(); if (line == null) break; else ... // elabora line}

✔ Si realizza un cicloinfinito while (true),dal quale si escesoltanto quando siverifica la condizioneall’interno del ciclo

✔ Nel caso di cicli annidati,l’enunciato break provoca laterminazione del ciclo piùinterno tra quelli in cui si trovaannidato l’enunciato stesso

39

Array riempiti solo in parte

40

Array riempiti solo in parte✔ Riprendiamo un problema già visto, rendendolo un po’ più

complesso✔ Scrivere un programma che

– legge dallo standard input una sequenza di numeri invirgola mobile, uno per riga, finché i dati non sonofiniti (ad esempio, i dati terminano inserendo una rigavuota)

– chiede all’utente un numero intero index e visualizza ilnumero che nella sequenza occupava la posizioneindicata da index

✔ La differenza rispetto al caso precedente è che ora nonsappiamo quanti saranno i dati introdotti dall’utente

41

Array riempiti solo in parte✔ Come risolvere il problema?

– per costruire un array è necessario indicarne ladimensione, che è una sua proprietà final

• gli array in Java non possono crescere!✔ Una possibile soluzione consiste nel costruire un array di

dimensioni sufficientemente grandi da poter accogliereuna sequenza di dati di lunghezza “ragionevole”, cioètipica per il problema in esame

✔ Al termine dell’inserimento dei dati da parte dell’utente, ingenerale, non tutto l’array conterrà dati validi– è necessario tenere traccia di quale sia l’ultimo indice

nell’array che contiene dati validi

42

Array riempiti solo in partefinal int ARRAY_LENGTH = 1000;double[] values = new double[ARRAY_LENGTH];ConsoleReader c = new ConsoleReader();int valuesSize = 0;String s;while(!(s = c.readLine()).equals("")) //stranezza{ values[valuesSize] = Double.parseDouble(s); valuesSize++;}// valuesSize è l’indice del primo dato non validoSystem.out.println("Inserisci un numero:");int index = Integer.parseInt(c.readLine());if (index < 0 || index >= valuesSize) System.out.println("Valore errato");else System.out.println(values[index]);

Page 8: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 8

43

Array riempiti solo in parte✔ values.length è il numero di valori memorizzabili,

valuesSize è il numero di valori memorizzati✔ La soluzione presentata ha però ancora una debolezza

– se la previsione del programmatore sul numeromassimo di dati inseriti dall’utente è sbagliata, ilprogramma si arresta con un’eccezione di tipoArrayIndexOutOfBoundsException

✔ Ci sono due possibili soluzioni– impedire l’inserimento di troppi dati, segnalando

l’errore all’utente– ingrandire l’array quando ce n’è bisogno

44

Array riempiti solo in parte// impedisce l’inserimento di troppi datifinal int ARRAY_LENGTH = 1000;double[] values = new double[ARRAY_LENGTH];ConsoleReader c = new ConsoleReader();int valuesSize = 0;String s;while(!(s = c.readLine()).equals("")){ if (valuesSize == values.length) { System.out.println("Troppi dati"); break; } values[valuesSize] = Double.parseDouble(s); valuesSize++;}...

45

Cambiare dimensione ad un array✔ Abbiamo già visto come sia impossibile

aumentare (o diminuire) la dimensione di un array✔ Ciò che si può fare è creare un nuovo array più

grande di quello “pieno” (ad esempio il doppio),copiarne il contenuto ed abbandonarlo, usando poiquello nuovo (si parla di array dinamico)

if (valuesSize == values.length){ double[] newValues = new double[valuesSize*2]; for (int i = 0; i < values.length; i++) newValues[i] = values[i]; values = newValues; // valuesSize non cambia}

46

Semplici algoritmi degli array

47

Trovare un valore particolare✔ Un tipico algoritmo applicato ad array consiste

nella ricerca all’interno dell’array di (almeno) unelemento avente determinate caratteristichedouble[] values = {1, 2.3, 4.5, 5.6};double target = 3;int index = 0;boolean found = false;while (index < values.length && !found) if (values[index] > target) found = true; else index++;if (found) System.out.println(values[index]);

48

Trovare un valore particolare

✔ Questo algoritmo trova soltanto il primo valoreche soddisfa la richiesta

✔ La variabile found è necessaria perché la ricercapotrebbe avere esito negativo

double[] values = {1, 2.3, 4.5, 5.6};double target = 3;int index = 0;boolean found = false;while (index < values.length && !found) if (values[index] > target) found = true; else index++;if (found) System.out.println(values[index]);

Page 9: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 9

49

Trovare il valore minore✔ Un altro algoritmo tipico consiste nel trovare

l’elemento con il valore minore (o maggiore) traquelli presenti nell’array

✔ In questo caso bisogna esaminare sempre l’interoarray

double[] values = {1, 2.3, 4.5, 5.6};double min = values[0];for (int i = 1; i < values.length; i++) if (values[i] < min) min = values[i];System.out.println(min);

50

Eliminare un elemento✔ L’eliminazione di un elemento da un array

richiede due algoritmi diversi– se l’ordine tra gli elementi dell’array non è importante

(cioè se l’array realizza il concetto astratto di insieme),allora è sufficiente copiare l’ultimo elementodell’array nella posizione dell’elemento da eliminare eridimensionare l’array (oppure usare la tecnica degliarray riempiti soltanto in parte)

double[] values = {1, 2.3, 4.5, 5.6};int indexToRemove = 1;values[indexToRemove] = values[values.length - 1];values = resize(values, values.length - 1);

51

Eliminare un elemento✔ Se l’ordine tra gli elementi deve, invece, essere

mantenuto, l’algoritmo è più complesso– tutti gli elementi il cui indice è maggiore dell’indice

dell’elemento da rimuovere devono essere spostatinella posizione con indice immediatamente inferiore,per poi ridimensionare l’array (oppure usare la tecnicadegli array riempiti soltanto in parte)

double[] values = {1, 2.3, 4.5, 5.6};int indexToRemove = 1;for (int i=indexToRemove; i<values.length-1; i++) values[i] = values[i + 1];values = resize(values, values.length - 1);

52

Eliminare un elemento

indexToRemove

Senza ordinamento

indexToRemove

Con ordinamento

i trasferimenti vannoeseguiti dall’alto in basso!

53

Inserire un elemento✔ Per inserire un elemento in un array nella

posizione voluta, se questa non è la primaposizione libera, bisogna “fargli spazio”– tutti gli elementi il cui indice è maggiore dell’indice

della posizione voluta devono essere spostati nellaposizione con indice immediatamente superiore, apartire dall’ultimo elemento dell’array

double[] values = {1, 2.3, 4.5, 5.6};values = resize(values, values.length + 1);int index = 2;for (int i = values.length - 1; i > index; i--) values[i] = values[i - 1];values[index] = 5.4;

54

Inserire un elemento

index

i trasferimenti vannoeseguiti dal basso in alto!

Page 10: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 10

55

Intervallo

���������������������

�������

������������

56

Array bidimensionali

57

✔ Riprendiamo un problema già visto– stampare una tabella con i valori delle potenze xy, per

ogni valore di x tra 1 e 4 e per ogni valore di y tra 1 e 5

e cerchiamo di risolverlo in modo più generale,scrivendo metodi che possano elaborare un’interastruttura di questo tipo

Array bidimensionali

1 1 1 1 12 4 8 16 323 9 27 81 2434 16 64 256 1024

58

✔ Una struttura di questo tipo, con dati organizzati inrighe e colonne, si dice matrice o arraybidimensionale

✔ Un elemento all’interno di una matrice èidentificato da una coppia (ordinata) di indici– un indice di riga– un indice di colonna

✔ In Java esistono gli array bidimensionali

Matrici 1 1 1 1 12 4 8 16 323 9 27 81 2434 16 64 256 1024

59

✔ Dichiarazione di un array bidimensionale conelementi di tipo int

✔ Costruzione di array bidimensionale di int con 4righe e 5 colonne

✔ Assegnazione di riferimento ad arraybidimensionale

✔ Accesso ad un elemento di un arraybidimensionale

Array bidimensionali in Java

int[][] powers;

new int[4][5];

powers = new int[4][5];

powers[2][3] = 2.0;

60

✔ Ciascun indice deve essere– intero– maggiore o uguale a 0– minore della dimensione corrispondente

✔ Per conoscere il valore delle due dimensioni– il numero di righe è

– il numero di colonne è (perché un array bidimensionale è in realtà un array di

array e ogni array rappresenta una colonna…)

Array bidimensionali in Java

powers.length;

powers[0].length;

Page 11: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 11

61

/** Programma che visualizza una tabella con i valori delle potenze "x alla y", con x e y che variano indipendentemente tra 1 ed un valore massimo assegnato dall’utente. I dati relativi a ciascun valore di x compaiono su una riga, con y crescente da sinistra a destra e x crescente dall’alto in basso.*/public class TableOfPowers{ public static void main(String[] args) { ConsoleReader c = new ConsoleReader(System.in); System.out.println( "Calcolo dei valori di x alla y"); System.out.println("Valore massimo di x:"); int maxX = c.readInt(); System.out.println("Valore massimo di y:"); int maxY = c.readInt(); int maxValue = (int)Math.pow(maxX, maxY); int columnWidth = 1 + Integer.toString(maxValue).length(); int[][] powers = generatePowers(maxX, maxY); printPowers(powers, columnWidth); } (continua)

62

(continua) /** Genera un array bidimensionale con i valori delle potenze di x alla y. */ public static int[][] generatePowers(int x, int y) { int[][] powers = new int[x][y]; for (int i = 0; i < x; i++) for (int j = 0; j < y; j++) powers[i][j] = (int)Math.pow(i + 1, j + 1); return powers; }(continua)

63

(continua) /** Visualizza un array bidimensionale di numeri interi con colonne di larghezza fissa e valori allineati a destra. */ public static void printPowers(int[][] v, int width) { for (int i = 0; i < v.length; i++) { for (int j = 0; j < v[0].length; j++) { String s = Integer.toString(v[i][j]); while (s.length() < width) s = " " + s; System.out.print(s); } System.out.println(); } }}

64

Scomposizione di stringhe

65

Scomposizione di stringhe✔ Tutti gli esempi visti fino ad ora prevedevano

l’inserimento dei dati in ingresso uno per riga,ma spesso è più comodo o più naturale per l’utenteinserire più dati per riga– ad esempio, cognome dello studente e voto

✔ Dato che readLine legge un’intera riga, bisognaimparare ad estrarre le sottostringhe relative aisingoli dati che compongono la riga– non si può usare substring, perché in generale non

sono note la lunghezza e la posizione di inizio deisingoli dati nella riga

66

Scomposizione di stringhe✔ Per la scomposizione di stringhe in sottostringhe

delimitate da spazi, è molto utile la classeStringTokenizer, che fa parte della libreriastandard ed appartiene al package java.util– una sottostringa con caratteristiche sintattiche ben

definite (ad esempio, delimitata da spazi…) si chiamatoken

– StringTokenizer considera come delimitatori disottostringhe gli spazi, i caratteri da tabulazione e icaratteri di “andata a capo”

Page 12: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 12

67

Scomposizione di stringhe✔ Per usare StringTokenizer, innanzitutto bisogna

creare un oggetto della classe fornendo la stringacome parametro al costruttore

✔ Successive invocazioni del metodo nextTokenrestituiscono successive sottostringhe, fin quandol’invocazione di hasMoreTokens restituisce true

String line = console.readLine();StringTokenizer t = new StringTokenizer(line);

while (t.hasMoreTokens()){ String token = t.nextToken(); // elabora token}

68

Esempioimport java.util.StringTokenizer;public class CountWords{ public static void main(String[] args) { ConsoleReader c = new ConsoleReader(); int count = 0; while (true) { String line = c.readLine(); if (line == null) break; else { StringTokenizer t = new StringTokenizer(line); while (t.hasMoreTokens()) { t.nextToken(); // non devo elaborare count++; } } } System.out.println(count + " parole"); }}

69

Il tipo di dati char

70

Caratteri in una stringa✔ Sappiamo già come estrarre sottostringhe da una

stringa, con il metodo substring✔ A volte è necessario estrarre ed elaborare

sottostringhe di dimensioni minime, cioè dilunghezza unitaria– una stringa di lunghezza unitaria contiene un solo

carattere, che può essere memorizzato in una variabiledi tipo char anziché in una stringa

– il tipo char in Java è un tipo di dato fondamentalecome i tipi di dati numerici ed il tipo boolean, cioè nonè una classe

71

Caratteri in una stringa✔ La presenza del tipo di dati char non è

strettamente necessaria in Java (ed è anche perquesto motivo che non l’avevamo ancora studiato)– infatti, ogni elaborazione che può essere fatta su

variabili di tipo char potrebbe essere fatta su stringhedi lunghezza unitaria

✔ L’uso del tipo char per memorizzare stringhe dilunghezza unitaria è però importante, perché– una variabile di tipo char occupa meno spazio in

memoria di una stringa di lunghezza unitaria– le elaborazioni su variabili di tipo char sono più veloci

72

Caratteri in una stringa✔ Il metodo charAt della classe String restituisce il

singolo carattere che si trova nella posizioneindicata dal parametro ricevuto– la convenzione sulla numerazione delle posizioni in una

stringa è la stessa usata dal metodo substring

✔ Una struttura di controllo che si usa spesso èl’elaborazione di tutti i caratteri di una stringa

String s = "John";char ch = s.charAt(2); // ch contiene 'h'

String s = "John";for (int i = 0; i < s.length(); i++){ char ch = s.charAt(i); // elabora ch}

Page 13: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 13

73

Caratteri in una stringa✔ Come si può elaborare un variabile di tipo char?

– la si può stampare passandola a System.out.print– la si può concatenare ad una stringa con l’operatore di

concatenazione + (verrà convertita in stringa, con lestesse regole della conversione dei tipi numerici)

✔ Una variabile di tipo char può anche essereconfrontata con una costante di tipo carattere– una costante di tipo carattere è un singolo carattere

racchiuso tra singoli apici (“apostrofo”)✔ Il singolo carattere può anche essere una

“sequenza di escape”

char ch = 'x';

char ch = '\u00E9'; // carattere 'è'char nl = '\n'; // carattere di "andata a capo"

74

Esempio: invertire una stringapublic class Reverse{ public static void main(String[] args) { ConsoleReader console = new ConsoleReader(); System.out.println("Inserire una stringa:"); String s = console.readLine(); String r = ""; for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); // aggiungi all’inizio r = ch + r; } System.out.println(s + " invertita è " + r); }}

75

��������������������������������

�������������������������������

76

Ordinamento

77

Motivazioni✔ Un problema davvero molto frequente nella elaborazione

dei dati consiste nell’ordinamento dei dati stessi, secondoun criterio prestabilito– nomi in ordine alfabetico, numeri in ordine crescente…

✔ Studieremo diversi algoritmi per l’ordinamento,introducendo anche uno strumento analitico per lavalutazione delle loro prestazioni

✔ Su dati ordinati è poi possibile fare ricerche in modomolto efficiente, e studieremo algoritmi adeguati

✔ Gli algoritmi che studieremo sono ricorsivi ed efficienti,ma non tutti gli algoritmi ricorsivi sono efficienti...

78

Ordinamento per selezione

Page 14: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 14

79

Ordinamento per selezione✔ Per semplicità, analizzeremo prima gli algoritmi

per ordinare un insieme di numeri (interi)memorizzato in un array– vedremo poi come si estendono semplicemente al caso

in cui si debbano elaborare oggetti anziché numeri

✔ Prendiamo in esame un array a da ordinare insenso crescente

11 9 17 5 12a[0] a[1] a[2] a[3] a[4]

5 9 11 12 17a[0] a[1] a[2] a[3] a[4]

80

5

Ordinamento per selezione

✔ Per prima cosa, bisogna trovare l’elemento minorepresente nell’array, come sappiamo già fare– in questo caso è il numero 5 in posizione a[3]

✔ Essendo l’elemento minore, la sua posizionecorretta nell’array ordinato è a[0]– in a[0] è memorizzato il numero 11, da spostare– non sappiamo quale sia la posizione corretta di 11

• lo spostiamo temporaneamente in a[3]– quindi, scambiamo a[3] con a[0]

11 9 17 12a[0] a[1] a[2] a[3] a[4]

5 9 17 11 12

81

Ordinamento per selezione

✔ La parte sinistra dell’array è già ordinata e non saràpiù considerata, dobbiamo ordinare la parte destra

✔ Ordiniamo la parte destra con lo stesso algoritmo– cerchiamo l’elemento minore, che è 9 in

posizione a[1]– dato che è già nella prima posizione a[1] della

parte da ordinare, non c’è bisogno di farescambi

5 9 17 11 12a[0] a[1] a[2] a[3] a[4]

la parte colorata dell’array ègià ordinata

5 9 17 11 12a[0] a[1] a[2] a[3] a[4]

82

11

Ordinamento per selezione

✔ Proseguiamo per ordinare la parte di array checontiene gli elementi a[2], a[3] e a[4]– l’elemento minore è il numero 11 in posizione a[3]– scambiamo a[3] con a[2]

5 9 17 12a[0] a[1] a[2] a[3] a[4]

5 9 11 17 12 175 9 11 12a[0] a[1] a[2] a[3] a[4]

83

17

Ordinamento per selezione

✔ Ora l’array da ordinare contiene a[3] e a[4]– l’elemento minore è il numero 12 in posizione a[4]– scambiamo a[4] con a[3]

✔ A questo punto la parte da ordinare contiene unsolo elemento, quindi è ovviamente ordinata

5 9 11 12a[0] a[1] a[2] a[3] a[4]

5 9 11 12 17 125 9 11 17a[0] a[1] a[2] a[3] a[4]

84

public class ArrayAlgorithms{ public static void selectionSort(int[] a) { for (int i = 0; i < a.length - 1; i++) { int minPos = findMinPos(a, i); if (minPos != i) swap(a, minPos, i); } } private static void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } private static int findMinPos(int[] a, int from) { int pos = from; for (int i = from + 1; i < a.length; i++) if (a[i] < a[pos]) pos = i; return pos; }}

Page 15: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 15

85

Ordinamento per selezione✔ L’algoritmo di ordinamento per selezione è

corretto ed è in grado di ordinare qualsiasi array– allora perché studieremo altri algoritmi di

ordinamento?– a cosa serve avere diversi algoritmi per

risolvere lo stesso problema?✔ Vedremo che esistono algoritmi di ordinamento

che, a parità di dimensioni del vettore da ordinare,vengono eseguiti più velocemente ���������

������������������ 86

Rilevazione delle prestazioni

87

Rilevazione delle prestazioni✔ Per valutare l’efficienza di un algoritmo si misura

il tempo in cui viene eseguito su insiemi di dati didimensioni via via maggiori

✔ Il tempo non va misurato con un cronometro,perché parte del tempo reale di esecuzione nondipende dall’algoritmo– caricamento della JVM– caricamento delle classi del programma– lettura dei dati dallo standard input– visualizzazione dei risultati

88

Rilevazione delle prestazioni✔ Il tempo di esecuzione di un algoritmo va misurato

all’interno del programma✔ Si usa il metodo statico

System.currentTimeMillis() che, ad ogni invocazione, restituisce un numero di

tipo long che rappresenta– il numero di millisecondi trascorsi da un evento di

riferimento (la mezzanotte del 1 gennaio 1970)✔ Ciò che interessa è la differenza tra due valori

– si invoca System.currentTimeMillis( ) prima e dopol’esecuzione dell’algoritmo

89

Rilevazione delle prestazioni✔ Proviamo ad eseguire

l’ordinamento di arraycon diverse dimensioni(n), contenenti numeriinteri casuali

✔ Si nota che l’andamentodel tempo di esecuzionenon è lineare– se n diventa il doppio, il

tempo diventa circa ilquadruplo!

n (migliaia)

tem

po (u

nità

rela

tive)

90

Rilevazione delle prestazioni✔ Le prestazioni dell’algoritmo di ordinamento per

selezione hanno quindi un andamento quadraticoin funzione delle dimensioni dell’array

✔ Le prossime domande che ci poniamo sono– è possibile valutare le prestazioni di un

algoritmo al punto di vista teorico?• senza realizzare un programma e senza eseguirlo

molte volte, per rilevarne i tempi di esecuzione edosservarne l’andamento

– esiste un algoritmo più efficiente perl’ordinamento?

Page 16: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 16

91

Analisi teorica delleprestazioni

92

Analisi teorica delle prestazioni✔ Il tempo d’esecuzione di un algoritmo dipende dal

numero e dal tipo di istruzioni in linguaggiomacchina che vengono eseguite dal processore

✔ Per fare un’analisi teorica– senza realizzare un algoritmo, compilarlo e tradurlo in

linguaggio macchina! dobbiamo fare delle semplificazioni drastiche

– facciamo un conteggio del numero di accessiad un elemento dell’array

93

Analisi teorica delle prestazioni✔ Ordiniamo con la selezione un array di n elementi

– per trovare l’elemento minore si fanno n accessi– per scambiare due elementi si fanno due accessi

• trascuriamo il caso in cui non serva lo scambio– in totale, (n+2) accessi

✔ A questo punto dobbiamo ordinare la parterimanente, cioè un array di (n-1) elementi– serviranno quindi ((n-1) + 2) accessi

e via così fino al passo con n=2, incluso

94

Analisi teorica delle prestazioni✔ Il conteggio totale degli accessi è quindi

(n+2)+((n-1)+2)+…+(3+2)+(2+2)

= n+(n-1)+…+3+2 + (n-1)*2

= n*(n+1)/2 - 1 + (n-1)*2

= 1/2*n2 + 5/2*n - 3

✔ Si ottiene quindi un’equazione di secondo gradoin n, che giustifica l’andamento parabolico deitempi rilevati sperimentalmente

n+(n-1)+…+3+2+1 = n*(n+1)/2

95

Analisi teorica delle prestazioni

✔ Facciamo un’ulteriore semplificazione, tenendopresente che ci interessano le prestazioni per valorielevati di n

✔ Se n vale 1000– 1/2*n2 vale 500000– 5/2*n - 3 vale 2497, circa 0.5% del totale

quindi diciamo che l’andamento temporaledell’algoritmo in funzione di n è 1/2*n2

1/2*n2 + 5/2*n - 3

96

Analisi teorica delle prestazioni

✔ Facciamo un’ulteriore semplificazione– ci interessa soltanto valutare cosa succede al tempo

d’esecuzione T(n)se n, ad esempio, raddoppia✔ In questo caso il tempo d’esecuzione quadruplica,

indipendentemente dal fattore 1/2 T(n) = 1/2*n2

T(2n) = 1/2*(2n)2 = 1/2*4*n2

= 4*T(n)

quindi l’andamento temporale è n2

1/2*n2

Page 17: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 17

97

Notazione “O grande”✔ Si dice quindi che

– per ordinare un array con l’algoritmo di selezione sieffettua un numero di accessi che è dell’ordine di n2

✔ Per esprimere sinteticamente questo concetto siusa la notazione “O grande” e si dice che ilnumero degli accessi è O(n2)

✔ Dopo aver ottenuto una formula che esprime l’andamentotemporale dell’algoritmo, si ottiene la notazione “Ogrande” considerando soltanto il termine che siincrementa più rapidamente all’aumentare di n,ignorando coefficienti costanti

98

Intervallo

���������������������

�����

������������

99

Ordinamento per fusione(MergeSort)

100

✔ Presentiamo ora un algoritmo di ordinamento(MergeSort) che vedremo avere prestazionimigliori di quelle dell’ordinamento per selezione

✔ Dovendo ordinare il vettore seguente

lo dividiamo in due parti (circa) uguali

MergeSort

5 7 9 1 8

5 7 9 1 8

101

✔ Se supponiamo che, come in questo caso, le dueparti siano già ordinate, è facile costruire il vettoreordinato, togliendo sempre il primo elemento dauno dei due vettori, scegliendo il più piccolo

MergeSort

5 7 9 1 8 1

5 7 9 1 8 1 5

5 7 9 1 8 1 5 7

5 7 9 1 8 1 5 7 8

5 7 9 1 8 1 5 7 8 9

102

✔ Ovviamente, nel caso generale le due parti delvettore non saranno ordinate

✔ Possiamo però ordinare ciascuna parte ripetendoil processo– dividiamo il vettore in due parti (circa) uguali– supponiamo che siano entrambe ordinate– uniamo le due parti nel modo appena visto

• questa fase si chiama fusione (merge)✔ Continuando così, arriveremo certamente ad una

situazione in cui le due parti sono davveroordinate– quando contengono un solo elemento!

MergeSort

Page 18: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 18

103

MergeSort✔ Si delinea quindi un algoritmo ricorsivo per

ordinare un array, chiamato MergeSort– se l’array contiene meno di due elementi, è già ordinato– altrimenti

• si divide l’array in due parti (circa) uguali• si ordina la prima parte usando MergeSort• si ordina la seconda parte usando MergeSort• si fondono le due parti ordinate usando l’algoritmo

di fusione (merge)

104

public class ArrayAlgorithms{ public static void mergeSort(int[] a) { // caso base if (a.length < 2) return; // dividiamo (circa) a meta’ int mid = a.length / 2; int[] left = new int[mid]; int[] right = new int[a.length - mid]; System.arraycopy(a, 0, left, 0, mid); System.arraycopy(a, mid, right, 0, a.length - mid); // passi ricorsivi per problemi piu’ semplici mergeSort(left); mergeSort(right); // fusione merge(a, left, right); } ...}

105

public class ArrayAlgorithms{ private static void merge(int[] a, int[] b, int[] c) { int ia = 0, ib = 0, ic = 0; while (ib < b.length && ic < c.length) if (b[ib] < c[ic]) a[ia++] = b[ib++]; else a[ia++] = c[ic++]; while (ib < b.length) a[ia++] = b[ib++]; while (ic < c.length) a[ia++] = c[ic++]; } ...}

106

Prestazioni di MergeSort

107

Prestazioni di MergeSort✔ Rilevazioni sperimentali delle prestazioni mostrano

che l’ordinamento con MergeSort è molto piùefficiente dell’ordinamento con selezione

✔ Cerchiamo di fare una valutazione teorica,calcolando il numero di accessi ai singoli elementidell’array che sono necessari per l’ordinamento

✔ Chiamiamo T(n) il numero di accessi necessariper ordinare un array di n elementi

108

Prestazioni di MergeSort✔ Le due invocazioni di System.arraycopy

richiedono complessivamente 2n accessi– tutti gli n elementi devono essere letti e scritti

✔ Le due invocazioni ricorsive richiedono T(n/2)ciascuna

✔ La fusione richiede– n accessi per scrivere gli n elementi dell’array

ordinato• ogni elemento da scrivere richiede la lettura

di due elementi, uno da ciascuno dei duearray da fondere, per un totale di 2n accessi

Page 19: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 19

109

Prestazioni di MergeSort✔ Sommando tutti i contributi si ottiene T(n) = 2T(n/2) + 5n

✔ La soluzione di questa equazione per ottenereT(n) in funzione di n non è semplice e va al dilà degli scopi di questo corso

✔ Si può però agevolmente verificare, persostituzione, che questa sia la soluzione T(n) = n + 5n*log2n

110

Prestazioni di MergeSort T(n) = n + 5n*log2n T(n) = 2T(n/2) + 5n

= 2(n/2 + 5n/2*log2(n/2)) + 5n

= n + 5n*log2(n/2) + 5n

= n + 5n*(log2n - log22) + 5n

= n + 5n*(log2n - 1) + 5n

= n + 5n*log2n - 5n + 5n

= n + 5n*log2n

111

Prestazioni di MergeSort

✔ Per determinare la notazione “O grande”,osserviamo che– il termine 5n*log2n cresce più

rapidamente del termine n– il fattore 5 è ininfluente, come tutti i fattori

moltiplicativi costanti

T(n) = n + 5n*log2n

T(n) = n log2n

112

Prestazioni di MergeSort

✔ Nelle notazioni “O grande” non si indica la basedei logaritmi, perché il logaritmo in una base sipuò trasformare nel logaritmo in un’altra base conun fattore moltiplicativo, che va ignorato

✔ Quindi, le prestazioni dell’ordinamento MergeSorthanno un andamento

che sono migliori di O(n2)

T(n) = n log2n

O(n log n)

113

���������������������

��������������������������������

114

Ricerca lineare

Page 20: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 20

115

Ricerca lineare✔ Abbiamo già visto un algoritmo da utilizzare per

individuare la posizione di un elemento che abbiaparticolari caratteristiche all’interno di un array icui elementi non siano ordinati

✔ Dato che bisogna esaminare tutti gli elementi, siparla di ricerca sequenziale o lineare

public class ArrayAlgorithms{ public static int linearSearch(int[] a, int v) { for (int i = 0; i < a.length; i++) if (a[i] == v) return i; // TROVATO return -1; // NON TROVATO } ...}

116

Ricerca lineare: prestazioni✔ Valutiamo le prestazioni dell’algoritmo di ricerca

lineare– se l’elemento cercato non è presente nell’array,

sono necessarie n visite– se l’elemento cercato è presente nell’array, il

numero di ricerche necessarie per trovarlodipende dalla sua posizione• in media saranno n/2

✔ In ogni caso, quindi, le prestazioni dell’algoritmosono O(n)

117

Ricerca binaria

118

Ricerca in un array ordinato✔ Il problema di individuare la posizione di un

elemento che abbia particolari caratteristicheall’interno di un array può essere affrontato inmodo più efficiente se l’array è ordinato

125 9 11 17a[0] a[1] a[2] a[3] a[4]

✔ Cerchiamo l’elemento 12

✔ Confrontiamo 12 con l’elemento che si trova(circa) al centro dell’array, a[2], che è 11

✔ L’elemento che cerchiamo è maggiore di 11– se è presente nell’array, sarà a destra di 11

21a[5]

119

125 9 11 17a[0] a[1] a[2] a[3] a[4]

21a[5]

Ricerca in un array ordinato

✔ A questo punto dobbiamo cercare l’elemento 12nel solo sotto-array che si trova a destra di a[2]

✔ Usiamo lo stesso algoritmo, confrontando 12 conl’elemento che si trova al centro, a[4], che è 17

✔ L’elemento che cerchiamo è minore di 17

– se è presente nell’array, sarà a sinistra di 17

120

✔ A questo punto dobbiamo cercare l’elemento 12nel sotto-array composto dal solo elemento a[3]

✔ Usiamo lo stesso algoritmo, confrontando 12 conl’elemento che si trova al centro, a[3], che è 12

✔ L’elemento che cerchiamo è uguale a 12– l’elemento che cerchiamo è presente

nell’array e si trova in posizione 3

125 9 11 17a[0] a[1] a[2] a[3] a[4]

21a[5]

Ricerca in un array ordinato

Page 21: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 21

121

✔ Se il confronto tra l’elemento da cercare el’elemento a[3] avesse dato esito negativo,avremmo cercato nel sotto-array vuoto a sinistra oa destra, concludendo che l’elemento cercato nonè presente nell’array

✔ Questo algoritmo si chiama ricerca binaria,perché ad ogni passo si divide l’array in due parti,e funziona soltanto se l’array è ordinato

125 9 11 17a[0] a[1] a[2] a[3] a[4]

21a[5]

Ricerca in un array ordinato

122

public class ArrayAlgorithms{ public static int binarySearch(int[] a, int v) { return binSearch(a, 0, a.length - 1, v); } private static int binSearch(int[] a, int from, int to, int v) { if (from > to) return -1; // NON TROVATO int mid = (from + to) / 2; // CIRCA IN MEZZO if (a[mid] == v) return mid; // TROVATO else if (a[mid] < v) // CERCA A DESTRA return binSearch(a, mid + 1, a.length, v); else // CERCA A SINISTRA return binSearch(a, from, mid - 1, v); } ...}

123

Ricerca binaria: prestazioni✔ Valutiamo le prestazioni dell’algoritmo di ricerca

binaria in un array ordinato– osserviamo che l’algoritmo è ricorsivo

✔ Per cercare in un array di dimensione n bisogna– effettuare un confronto (con l’elemento centrale)– effettuare una ricerca in un array di dimensione n/2

✔ Quindi

T(n) = T(n/2) + 1

124

Ricerca binaria: prestazioni

✔ La soluzione di questa equazione per ottenereT(n) in funzione di n non è semplice e va al di làdegli scopi di questo corso

✔ Si può però agevolmente verificare, persostituzione, che questa sia la soluzione T(n) = 1 + log2n

✔ Le prestazioni dell’algoritmo sono quindi miglioridi quelle della ricerca lineare

T(n) = T(n/2) + 1

O(log n)

125

Intervallo

���������������������

������������

126

Leggere l’input nellinguaggio Java standard

Page 22: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 22

127

Gestione dell’input standard✔ Per la gestione dell’input e dell’output in Java si

utilizzano classi del pacchetto java.io della libreriastandard

✔ L’accesso all’input standard avviene mediantel’oggetto System.in della classe InputStream

✔ La classe InputStream non ha metodi per leggerenumeri o stringhe, ha solo il metodo read chelegge un singolo byte

128

Gestione dell’input standard✔ Per usare direttamente System.in, senza ricorrere a

ConsoleReader, dobbiamo risolvere tre problemi– System.in consente di leggere byte, mentre noi abbiamo

bisogno di leggere caratteri e righe di input• questo problema verrà risolto creando un oggetto della classe

BufferedReader e invocando il suo metodo readLine

– se il metodo readLine trova un errore durante la letturadell’input, genera una cosiddetta eccezione

• dobbiamo dire al compilatore come gestire tale eccezione

– il metodo readLine restituisce sempre una stringa• se vogliamo leggere numeri, dobbiamo convertire la stringa

129

Leggere caratteri invece di byte✔ Alcuni schemi di codifica dei caratteri usano un

solo byte per rappresentare un carattere (es. ASCII)✔ Sappiamo però che Java usa lo schema Unicode,

che rappresenta ciascun carattere con due byte✔ La gestione dell’input in Java usa due diverse

categorie di oggetti– i flussi di input (input stream) leggono sequenze di byte– i lettori (reader) leggono sequenze di caratteri

ed è possibile trasformare un flusso in un lettore

130

Leggere caratteri invece di byte✔ Per trasformare un flusso di input in un lettore si

usa la classe InputStreamReader

✔ Gli oggetti della classe InputStreamReaderleggono caratteri, ma leggono un carattere allavolta, mentre noi vogliamo leggere un’intera rigadi input, fino al carattere Invio– questo si può fare, leggendo un carattere alla volta e poi

componendo la stringa totale, ma è scomodo

InputStreamReader reader = new InputStreamReader(System.in);

131

Leggere caratteri invece di byte✔ La classe BufferedReader trasforma un lettore a

caratteri singoli in un lettore con buffer(“bufferizzato”), che può leggere una riga per volta

✔ Gli oggetti della classe BufferedReader possonoessere usati per invocare il metodo readLine

BufferedReader console = new BufferedReader(reader);

System.out.println("Inserire il nome");String firstName = console.readLine();

132

Leggere caratteri invece di byte✔ Riassumendo:

✔ L’oggetto di tipo InputStreamReader vieneutilizzato soltanto per costruire l’oggetto di tipoBufferedReader, quindi può venire passatodirettamente senza memorizzarlo in una variabile

BufferedReader console = new BufferedReader( new InputStreamReader(System.in));System.out.println("Inserire il nome");String firstName = console.readLine();

Page 23: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 23

133

Gestire le eccezioni di input✔ Quando si leggono dati da un flusso di input, in

generale, possono verificarsi problemi– se l’input proviene da un file su disco, il disco può

essere difettoso– se l’input proviene da una connessione di rete, la

connessione può interrompersi durante la lettura✔ Questi problemi non si verificano se l’input

proviene dalla tastiera, ma la gestione dell’inputeffettuata dalla classe InputStream è omogenea eindipendente dal tipo di flusso

134

Gestire le eccezioni di input✔ Il meccanismo utilizzato dal linguaggio Java per

reagire in caso di errori inattesi è quello di generare(o lanciare, throw) eccezioni (exception)– nel nostro esempio, l’eccezione è generata dal metodo

read della classe InputStream, e viene “propagata” dalmetodo readLine della classe BufferedReader

✔ Quando un metodo segnala che la sua invocazionepuò generare un’eccezione, il compilatore richiedeche il programmatore indichi esplicitamente come ilsuo programma intende gestire tale eccezione

135

Gestire le eccezioni di input// NON FUNZIONA!import java.io.InputStreamReader;import java.io.BufferedReader;public class ReadInput{ public static void main(String[] args) { BufferedReader console = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Inserire il nome"); String name = console.readLine(); }}

ReadInput.java:10:unreported exception java.io.IOException;must be caught or declared to be thrown

136

✔ Ci sono diversi metodi per gestire le eccezioni✔ Per il momento, usiamo il metodo più semplice

– intercettiamo (catch) l’eccezione quando si verifica,usando un blocco try con una clausola catch, eterminiamo l’esecuzione del programma con unasegnalazione d’errore

Gestire le eccezioni di input

try { String name = console.readLine();}catch (IOException e){ System.out.println(e); System.exit(1);}

137

✔ In questo caso, se viene generata l’eccezione, ilprogramma stampa sull’output standard ladescrizione testuale standard dell’eccezione

ed il programma termina l’esecuzione segnalandoche qualcosa non ha funzionato correttamente

Gestire le eccezioni di inputcatch (IOException e){ System.out.println(e); System.exit(1);}

System.out.println(e);

System.exit(1); Invece, System.exit(0)termina l’esecuzione segnalandoche tutto è andato bene

138

import java.io.IOException;import java.io.BufferedReader;import java.io.InputStreamReader;public class MakePassword3{ public static void main(String[] args) { try { BufferedReader c = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Inserire il nome"); String firstName = c.readLine(); System.out.println("Inserire il cognome"); String lastName = c.readLine(); System.out.println("Inserire l’età"); int age = Integer.parseInt(c.readLine());(continua)

Esempio

Page 24: Il calcolo del fattoriale - spazioinwind.libero.itspazioinwind.libero.it/inginfotv/appunti/fondinfo1/pdf/Settimana4... · Il calcolo del fattoriale La funzione fattoriale, molto usata

Fondamenti di Informatica 1 Settimana 4

Marcello Dalpasso 24

139

(continua) String initials = firstName.substring(0, 1) + lastName.substring(0, 1); String pw = initials.toLowerCase() + age; System.out.println("La password è " + pw); } catch (IOException e) { System.out.println(e); System.exit(1); } }}

Esempio

140

��������������������������������

��������������������������