Fondamenti di Informatica 1 Prof. B.Buttarazzi A.A. 2010/2011
Sommario Effetti collaterali Metodi ricorsivi Esercizi proposti 19/04/2011 2
import javax.swing.joptionpane; public class esempioarrayg{ public static void main(string[] args) { // TODO Auto-generated method stub int numero; do { String s = JOptionPane.showInputDialog("Immettere dimensione array "); numero=integer.parseint(s); while (numero<=0); int A[] = new int[numero]; //lettura array for (int i=0;i<numero;i++) { A[i] = Integer.parseInt(JOptionPane.showInputDialog((i +1)+" numero")); ; //scrittura array String array =""; for (int i=0;i<a.length;i++) { array += A[i] ; if (i+1!=a.length) { array +=" "; JOptionPane.showMessageDialog(null," l'array inserito è: ["+array+"]");
Esempi di definizione di metodi public static void leggiarray(int [] B) { /* legge uno alla volta gli elementi dell array B; utilizza pesantemente e positivamente gli effetti collaterali */ int i; // la variabile di iterazione /* ciclo di lettura degli elementi dell array */ for (i = 0; i < B.length; i++) { B[i] = Integer.parseInt(JOptionPane.showInputDialog((i +1)+" numero")); public static String stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; return S;
Esempi di definizione di metodi public static void leggiarray(int [] B) { /* legge uno alla volta gli elementi dell array B; utilizza pesantemente e positivamente gli effetti collaterali */ int i; // la variabile di iterazione /* ciclo di lettura degli elementi dell array */ for (i = 0; i < B.length; i++) { B[i] = Integer.parseInt(JOptionPane.showInputDialog((i +1)+" numero")); public static String stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; return S; tipo di ritorno propietà del metodo parametri del metodo nome del metodo
Esempi di definizione di metodi public static void leggiarray(int [] B) { /* legge uno alla volta gli elementi dell array B; utilizza pesantemente e positivamente gli effetti collaterali */ int i; // la variabile di iterazione /* ciclo di lettura degli elementi dell array */ for (i = 0; i < B.length; i++) { B[i] = Integer.parseInt(JOptionPane.showInputDialog((i +1)+" numero")); public static String stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; return S; tipo di ritorno propietà del metodo parametri del metodo nome del metodo
Esempi di chiamata di metodi public class esempioleggiarray { public static void main(string args[]) throws NumberFormatException, IOException { int numero; do { String s = JOptionPane.showInputDialog("Immettere dimensione array "); numero=integer.parseint(s); while (numero<=0); int A[] = new int[numero]; //lettura array leggiarray(a); //stampa array JOptionPane.showMessageDialog(null," l'array inserito è: ["+stampaarray(a)+"]"); Chiamata del metodo
Esempi di chiamata di metodi public class esempioleggiarray { public static void main(string args[]) throws NumberFormatException, IOException { int numero; do { String s = JOptionPane.showInputDialog("Immettere dimensione array "); numero=integer.parseint(s); while (numero<=0); int A[] = new int[numero]; //lettura array leggiarray(a); //stampa array JOptionPane.showMessageDialog(null," l'array inserito è: ["+stampaarray(a)+"]"); Chiamata del metodo
Flusso di controllo main ( ) leggiarray (int [] B ) leggiarray(a); L esecuzione del main : si interrompe al momento della chiamata del metodo viene eseguito il passaggio dei parametri (B=A) viene eseguito il metodo invocato ; 19/04/2011 e si prosegue dalla prima istruzione seguente la chiamata. 9
Effetti collaterali Si dice che un metodo causa un effetto collaterale quando esso modifica una variabile al di fuori del proprio campo di visibilità (scope). In Java si può verificare un effetto collaterale SOLO se il parametro formale di un metodo è un oggetto (es. un array).
public class effetticollaterali1 { public static void main(string[] args) { // TODO Auto-generated method stub int[] a={4,5,6; //test (a); stampaarray (a); public static void test (int [] x) { x[0] =0; x[1] ++; public static void stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; System.out.println(S); output:0 6 6 public class effetticollaterali2 { public static void main(string[] args) { // TODO Auto-generated method stub int[] a={4,5,6; test (a[0],a[1]); stampaarray (a); public static void test (int x, int y) { x =0; y ++; public static void stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; System.out.println(S); Output: 4 5 6
public class effetticollaterali1 { public static void main(string[] args) { // TODO Auto-generated method stub int[] a={4,5,6; //test (a); stampaarray (a); public static void test (int [] x) { x[0] =0; x[1] ++; public static void stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; System.out.println(S); output:0 6 6 public class effetticollaterali2 { public static void main(string[] args) { // TODO Auto-generated method stub int[] a={4,5,6; test (a[0],a[1]); stampaarray (a); public static void test (int x, int y) { x =0; y ++; public static void stampaarray (int V[]) { String S =""; for (int i=0;i<v.length;i++) { S += V[i] ; if (i+1!=v.length) { S +=" "; System.out.println(S); Output: 4 5 6 In questo caso viene passato in input un array quindi è passato il riferimento agli elementi, che permette di modificare le variabili del vettore a esterno al metodo (questo è un effetto collaterale)
Effetti collaterali Un effetto collaterale non è necessariamente una situazione di errore o un problema, se gestito correttamente può essere una soluzione per risolvere particolari tipi di situazioni come ad esempio la lettura di un array.
Esercizio Scrivere un metodo statico che stampa una matrice per righe 19/04/2011 14
Esercizio Scrivere un metodo statico che stampa una matrice per colonne 19/04/2011 15
public class matrice { /** * @param args */ public static void main(string[] args) { // TODO Auto-generated method stub int[][] A = { // crea matrice A con dimensione 2x3 { 1, 2, 3, // riga 0 di A { 4, 5, 6 // riga 1 di A ; stamparighematrice(a); // stampa la matrice per righe System.out.println(); stampacolonnematrice(a); // stampa la matrice per colonne public static void stamparighematrice(int[][] M) { for (int i=0; i<m.length; i++) { // scandisce righe for (int j=0; j<m[0].length; j++) // scandisce elementi riga i System.out.print(M[i][j]+" "); // stampa elemento riga System.out.println(); // fine riga Soluzioni Output prodotto 1 2 3 4 5 6 1 4 2 5 3 6 public static void stampacolonnematrice(int[][] N) { for (int j=0; j<n[0].length; j++) { // scandisce colonne for (int i=0; i<n.length; i++) // scandisce elementi colonna j System.out.print(N[i][j]+" "); // stampa elemento colonna System.out.println(); // fine colonna
Esercizi proposti 1. Scrivere un metodo che data una matrice genera la trasposta. 19/04/2011 17
Domande teoriche proposte 1) Descrivere le modalità di passaggio dei parametri per VALORE 2) Spiegare perché in Java pur passando un array per valore si può ottenere un effetto collaterale.
La ricorsione In Java ogni metodo può chiamare anche se stesso, secondo una tecnica detta ricorsione. Ovviamente tali metodi devono sempre contenere un istruzione di controllo che ha il compito di interrompere la successione delle chiamate, se si verificano certe condizioni. 19/04/2011 19
Il calcolo del fattoriale La funzione fattoriale di n, per n=0 vale 1, per n>0 può essere definita con il prodotto dei fattori da 1 a n: n!= 1*2*3* (n-1)*n 0!=1 n è un numero intero non negativo 19/04/2011 20
Il calcolo del fattoriale La funzione fattoriale, può essere definita anche in modo ricorsivo: n! 1 n( n 1)! se se n n 0 0 dove n è un numero intero non negativo 19/04/2011 21
Il calcolo del fattoriale Cerchiamo di capire cosa significa la ricorsione 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 19/04/2011 22
Il calcolo del fattoriale Scriviamo un metodo per calcolare il fattoriale iterativo 19/04/2011 23
public static float fattoriale (int n) { float F=1; int i=1; do { F=F*i; i=i+1; while (i<=n); return F; 19/04/2011 24
19/04/2011 25
Il calcolo del fattoriale ricorsivo Se realizziamo il metodo partendo direttamente dalla sua definizione, è più naturale scrivere { public static float fattoriale (int n) float f; if (n == 0) f = 1; else f = n * fattoriale(n - 1); return f; 19/04/2011 26
La ricorsione Invocare un metodo mentre si esegue lo stesso metodo è un paradigma di programmazione che si chiama ricorsione e un metodo che ne faccia uso si chiama metodo ricorsivo La ricorsione è uno strumento molto potente per realizzare alcuni algoritmi, ma può essere fonte di errori di difficile diagnosi 19/04/2011 27
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 azioni che vengono eseguite quando viene invocato un metodo qualsiasi cioè: sospende l esecuzione del metodo invocante (le variabili locali rimangono congelate) esegue il metodo invocato fino alla sua terminazione (con nuove variabili locali) riprende l esecuzione del metodo invocante dal punto in cui era stata sospesa (recuperando le variabili locali) 19/04/2011 28
La ricorsione Vediamo la sequenza usata per calcolare 3! si invoca f(3) f(3) invoca f(2) f(2) invoca f(1) f(1) invoca f(0) f(0) restituisce 1 f(1) restituisce 1 f(2) restituisce 2 f(3) restituisce 6 Si crea quindi una lista ( stack) di metodi in attesa, ciascuno con le sue variabili locali, che si allunga e che poi si accorcia fino ad estinguersi 19/04/2011 29
La ricorsione Anche se il meccanismo di funzionamento della ricorsione può sembrare complesso, in realtà esistono solo due regole ben definite che vanno utilizzate per scrivere metodi ricorsivi che funzionino 19/04/2011 30
Prima regola il metodo ricorsivo deve fornire la soluzione del problema in almeno un caso particolare, senza ricorrere ad una chiamata ricorsiva tale caso si chiama caso base della ricorsione nel nostro esempio, il caso base era if (n == 0) return 1; a volte ci sono più casi base, non è necessario che il caso base sia unico 19/04/2011 31
Seconda regola il metodo ricorsivo deve effettuare la chiamata ricorsiva dopo aver semplificato il problema (questa fase si chiama passo ricorsivo) nel nostro esempio si ha il passo ricorsivo all interno di una espressione f = n * fattoriale(n - 1); 19/04/2011 32
Seconda regola il metodo ricorsivo deve effettuare la chiamata ricorsiva dopo aver semplificato il problema (questa fase si chiama passo ricorsivo) nel nostro esempio si ha il passo ricorsivo all interno di una espressione f = n * fattoriale(n - 1); ad ogni invocazione il problema diventa sempre più semplice e si avvicina al caso base la soluzione del caso base non richiede ricorsione 19/04/2011 33
Ricorsione infinita Si noti che non tutti i metodi ricorsivi realizzano algoritmi corretti 1. se manca il caso base, il metodo ricorsivo continua ad invocare se stesso all infinito 2. se il problema non viene semplificato ad ogni invocazione ricorsiva, il metodo ricorsivo continua ad invocare se stesso all infinito In queste 2 ipotesi la lista dei metodi in attesa si allunga indefinitamente, l ambiente runtime esaurisce la memoria disponibile per tenere traccia di questa lista, e il programma termina con un errore 19/04/2011 34
Esempio di Funzione ricorsiva Funzione non ricorsiva n!= 1*2*3*...*(n-1)*n fatt(n)= 1*2*3*...*(n-1)*n; Funzione ricorsiva 0!=1 n!= n*(n-1)!; fatt(n)=n*fatt(n-1) 19/04/2011 35
public static float fattoriale (int n) { float F=1; int i=1; do { F=F*i; i=i+1; while (i<=n); return F; 19/04/2011 36
{ public static float fattoriale (int n) float f; if (n == 0) f = 1; else f = n * fattoriale(n - 1); return f; La funzione ricorsiva fattoriale non necessita di iterazioni, ma include internamente il calcolo del risultato, infatti restituisce 1 se il parametro ricevuto è minore o uguale di 1 (cioè vale 0 o 1), mentre in caso contrario il valore restituito è il prodotto di n per il fattoriale di n-1, pertanto fattoriale calcola il valore da restituire chiamando se stesso e "passandosi" come parametro il parametro appena ricevuto, diminuito di uno. 19/04/2011 37
Esercizio Scrivere un metodo statico ricorsivo che calcola la funzione di fibonacci 19/04/2011 38
Per esercizio avevamo già codificato tale funzione in modo iterativo /* algoritmo iterativo */ public static long iterfibonacci(int n){ if(n<=1) return n; long x=0; long y=1; long tmp; for(int i=2; i<=n; i++){ tmp = x; x = y; y = tmp+x; return y; 19/04/2011 39
19/04/2011 40
L uso della ricorsine semplifica la soluzione ma talvolta può essere molto costoso e inefficiente dal punto di vista computazionale. Infatti ogni chiamata ne produce altre due: alcune di queste chiamate sono uguali. fibo(5) fibo(4) fibo(3) fibo(3) fibo(2) fibo(2) fibo(1) fibo(2) fibo(1) fibo(1) fibo(0) fibo(1) fibo(0) fibo(1) fibo(0) Ogni chiamata esegue una somma eccetto quelle che corrispondono alle foglie dell albero binario delle chiamate: in totale si fanno 7 somme e 15 chiamate. Più efficiente è l implementazione che svolge la ricorsione, implementandola come un PROCEDIMENTO ITERATIVO. Con una sola chiamata vengono eseguite nel caso dell esempio le quattro somme 19/04/2011 41
.osservazioni alla semplicità del codice corrisponde una maggiore complessità dell algoritmo (che impareremo a calcolare quando studieremo la complessità). Per il momento basta osservare che ad ogni chiamata vengono generate 2 variabili quindi si occupa più memoria. 19/04/2011 42
Esercizio Scrivere un metodo che calcola la funzione di elevamento a potenza tra due interi in modo ricorsivo 19/04/2011 43
Esercizio Sommare tutti gli elementi della matrice M 19/04/2011 44
Esercizio Sommare tutti gli elementi della colonna k- esima della matrice M 19/04/2011 45
Esercizi proposti 1. Realizzare un metodo che data una matrice verifica se è simmetrica 19/04/2011 46
Esercizi proposti 1. Realizzare un metodo che data una matrice verifica se è unitaria 19/04/2011 47
Esercizi proposti 1. Realizzare un metodo che restituisce la posizione del minimo di un array compreso nell'intervallo di indici "inizio" e "fine" 19/04/2011 48
Esercizi proposti 1. Realizzare un metodo per la moltiplicazione di 2 matrici A e B. 19/04/2011 49
Esempio
Esercizi proposti 1. Realizzare un metodo che presa in input una matrice 10x10 la inizializza con i dati della tavola pitagorica 19/04/2011 51
Esercizi proposti 1. Realizzare un metodo che presi in input due array ordinati li fonde. 19/04/2011 52
Esercizi proposti 1. Realizzare un metodo che preso in input un intero N e una matrice NxN restituisce la matrice NxN con i numeri da 1 a N 2 disposti a spirale per la moltiplicazione di matrici 19/04/2011 53
Analisi del problema
Il problema del cambio di direzione
Il problema del cambio di direzione
Come aggiornare gli indici
Esercizio proposto Scrivere una programma Java che realizza il gioco indovina che numero ho pensato, descritto come segue: inizialmente, il programma genera un numero casuale intero compreso tra 1 e 100 e lo sceglie, e poi chiede all utente di indovinare il numero scelto dopo ciascun tentativo di risposta dell utente, l applicazione deve segnalare se la risposta data è giusta, oppure il numero è maggiore oppure il numero è minore rispetto al numero scelto il programma deve continuare a chiedere numeri all utente fino a che questi non abbia dato la risposta corretta, oppure abbia scelto di rinunciare ad indovinare (digitando il numero 0) se l utente indovina il numero scelto, il programma deve congratularsi con l utente, visualizzando anche il numero di tentativi fatti dall utente
Ad esempio, se il numero scelto dal programma fosse 21, l interazione tra applicazione e utente potrebbe essere la seguente Ho pensato un numero intero compreso tra 1 e 100. Indovina che numero ho pensato: 40 40 è troppo alto. Indovina che numero ho pensato: 30 30 è troppo alto. Indovina che numero ho pensato: 20 20 è troppo basso. Indovina che numero ho pensato: 22 22 è troppo alto. Indovina che numero ho pensato: 21 Bravo! Hai indovinato facendo 5 tentativi!