Corso di Laurea Ingegneria Informatica Fondamenti di Informatica Dispensa E12 Esercizi su ricorsione A.Miola Marzo 2012 http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 1 Contenuti q Applicazione di test per fattoriale q Calcolo del numero di attivazioni nel fattoriale q Definizione ricorsiva per il MCD q Elevamento a potenza di un numero q Applicazione di test per Stringa palindroma q Ricorsione su array q Calcolo di una sottosequenza di una sequenza data q Applicazione di test per calcolo dei numeri di Fibonacci q Applicazione di test per Hanoi con stampa dell’evoluzione dei perni con “piramide di * ” http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 2 Test Fattoriale . . . q Verificare il metodo ricorsivo per il calcolo della funzione fattoriale e commentare le soluzioni : public class Fattoriale { public static int fattoriale(int n) { int f; if (n == 0) f = 1; else f = n * fattoriale(n - 1); return f; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 3 . . . Test Fattoriale public static void testFattoriale() { System.out.println(“4! = “ + fattoriale(4)); System.out.println(“10! = “ + fattoriale(10)); System.out.println(“20! = “ + fattoriale(20)); System.out.println(“50! = “ + fattoriale(50)); System.out.println(“100! = “ + fattoriale(100)); } // . . . public static void main(String[] args) { testFattoriale(); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 4 Sempre sul Fattoriale . . . q Il numero di attivazioni del metodo fattoriale con il valore n del parametro è pari a n+1 q Definire un metodo attFattoriale per il calcolo ricorsivo del numero di attivazioni del metodo fattoriale avvenute durante la sua esecuzione § Il metodo attFattoriale usa il metodo fattoriale già definito 1 se n = 0 att(n) = 1 + att(n-1) http://www.dia.uniroma3.it/~java/fondinf/ se n > 0 Esercizi Ricorsione 5 Metodo attFattoriale public static int attFattoriale(int n) { int f; // valore del fattoriale int na; // numero attivazioni if (n == 0) { f = 1; na = 1; } else { f = n * fattoriale(n - 1); na = 1 + attFattoriale(n - 1); } return na; // ritorno numero attivazioni } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 6 Un’altra versione del Metodo attFattoriale /* Calcolo delle attivazioni senza l’uso del metodo fattoriale */ public static int attFattoriale(int n) { // int f; valore del fattoriale int na; // numero attivazioni if (n == 0) // f = 1; na = 1; else // f = n * fattoriale(n - 1); na = 1 + attFattoriale(n - 1); return na; // ritorno numero attivazioni } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 7 Ancora sul Fattoriale . . . q Definire e testare un metodo fattoriale per il calcolo ricorsivo che oltre al risultato della funzione calcoli anche il numero di attivazioni del metodo avvenute durante l’esecuzione http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 8 . . . Ancora sul Fattoriale . . . q Problema: dato un interno n si vuole calcolare ricorsivamente la funzione fattoriale e il numero di attivazioni del metodo per il relativo calcolo q Dati di ingresso: § Un intero n q Pre-condizioni: § n ≥ 0 q Dati di uscita: § Valore funzione fattoriale di n § Numero di attivazioni http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione ATTENZIONE ! 9 . . . Ancora sul Fattoriale . . . q Si richiede di calcolare 2 valori § Valore funzione fattoriale di n § Numero di attivazioni q IMPOSSIBILE ! – Ovviamente non posso definire un metodo che ritorna 2 valori public static int int fatt_att(int n) { int na ; // numero attivazioni int f; // valore del fattoriale di n if (n == 0) { na = 1; f = 1; } else {na = 1 + fatt_att(n-1); f = n * fatt_att(n - 1); } return na, f; } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 10 Una possibile soluzione q Allora devo trovare un’altra soluzione q Ad esempio posso introdurre un oggetto q In particolare posso definire una classe Contatore, per gestire oggetti capaci di “contare”, che ha una variabile d’istanza cont che serve a contare e che ha due metodi d’istanza per accedere al valore della variabile cont e per modificare il valore della variabile cont http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 11 La classe Contatore public class Contatore { int cont; public Contatore (int n) {this.cont = n;} public int getContatore() {return this.cont;} public void setContatore(int n) {this.cont = n;} } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 12 Una nuova classe Fattoriale q A questo punto posso definire una nuova classe Fattoriale , per calcolare il fattoriale di un numero, che usa un oggetto Contatore per calcolare (contare) il numero di attivazioni del metodo q In particolare definisco un metodo int attFattoriale(int n, Contatore na) § che calcola e restituisce il valore del fattoriale(n) § e che conta il numero delle sue attivazioni utilizzando un oggetto Contatore q Completo opportunamente la classe con un adeguato metodo di test http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 13 La nuova classe Fattoriale . . . public class Fattoriale { public static void main(String[] args) { testAttFattoriale(); } public static int attFattoriale(int n, Contatore na) { int f; // valore del fattoriale if (n == 0) { f = 1; na.setContatore(na.getContatore() + 1); } else { f = n * attFattoriale(n - 1,na); na.setContatore(na.getContatore() + 1); } return f; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 14 . . . La nuova classe Fattoriale System.out.println("numero attivazioni “ + cont.getContatore()); . . . segue . . . public static void testAttFattoriale() { Contatore cont; cont = new Contatore(0); System.out.println("4! = " + attFattoriale(4,cont)); System.out.println("numero attivazioni “ + cont.getContatore()); cont.setContatore(0); System.out.println("10! = " + attFattoriale(10,cont)); cont.setContatore(0); System.out.println("100! = " + attFattoriale(100,cont)); System.out.println("numero attivazioni “ + cont.getContatore()); }}http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 15 Un’altra soluzione . . . q Potrei anche trovare un’altra soluzione q In questo caso uso una variabile di classe q In particolare posso definire una classe Fattoriale, che ha una variabile di classe natt che serve a contare il numero di attivazioni, e che ha un metodo per restituire il valore della variabile natt q Definisco anche un metodo int fattorialeConAtt(int n) § che serve a inizializzare la variabile natt § e che si limita a invocare un metodo di supporto privato definito ricorsivamente che ad ogni invocazione incrementa natt int fattConAtt(int n) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 16 Un’altra nuova classe Fattoriale . . . public class Fattoriale { static int natt; // variabile per numero attivazioni public static int numeroAttivazioni() { // metodo di accesso alla variabile di conteggio return natt; } public static void main(String[] args) { testFattoriale(); } public static int fattorialeConAtt(int n) { natt = 0; // inizializza numero di attivazioni return fattConAtt(n); } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 17 . . . Un’altra nuova classe Fattoriale . . . . . . segue . . . private static int fattConAtt(int n) { System.out.println("In fattConAtt("+n+")"); int f; natt++; if (n == 0) { System.out.println("Finito"); f = 1; } else { System.out.println("Attivazione di fattConAtt("+(n-1)+")"); f = n*fattConAtt(n-1); System.out.println("Termine di fattConAtt("+n+")"); } return f; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 18 . . . Un’altra nuova classe Fattoriale . . . segue . . . public static void testFattoriale() { System.out.println("fattoriale 5 = "+ Fattoriale.fattorialeConAtt(5)); System.out.println("attivazioni fattoriale 5 = "+ Fattoriale.numeroAttivazioni()); System.out.println("fattoriale 1 = "+ Fattoriale.fattorialeConAtt(1)); System.out.println("attivazioni fattoriale 1 ="+ Fattoriale.numeroAttivazioni()); System.out.println("fattoriale 0 ="+ Fattoriale.fattorialeConAtt(0)); System.out.println("attivazioni fattoriale 0 = "+ Fattoriale.numeroAttivazioni()); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 19 Output . . . In fattConAtt(5) Attivazione di fattConAtt(4) In fattConAtt(4) Attivazione di fattConAtt(3) In fattConAtt(3) Attivazione di _fattConAtt(2) In fattConAtt(2) Attivazione di _fattConAtt(1) In fattConAtt(1) Attivazione di _fattConAtt(0) In fattConAtt(0) Finito (. . . segue . . .) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione Per il fattoriale di 5 ci sono 6 diverse attivazioni del metodo fattConAtt 20 . . . Output . . . Termine di fattConAtt(1) Termine di fattConAtt(2) Termine di fattConAtt(3) Termine di fattConAtt(4) Termine di fattConAtt(5) fattoriale 5 = 120 attivazioni fattoriale 5 = 6 (. . . segue . . .) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 21 . . . Output In fattConAtt(1) Attivazione di fattConAtt(0) In fattConAtt(0) Finito Termine di fattConAtt(1) fattoriale 1 = 1 attivazioni fattoriale 1 = 2 In fattConAtt(0) Finito fattoriale 0 = 1 attivazioni fattoriale 0 = 1 http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 22 Massimo Comun Divisore . . . q Definire e verificare un metodo ricorsivo per il calcolo della funzione mcd(x,y), con x e y numeri naturali e con x > y, sfruttando la seguente definizione : x se y = 0 – passo base mcd(y, r) se y > 0 e x = q·y+r, con 0 ≤ r < y passo induttivo mcd(x,y) = http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 23 . . . Massimo Comun Divisore . . . public class MCD { public static int mcd(int x, int y) { // pre : x >= y >= 0 int r, ret; if (y == 0) ret = x; // caso base else { // caso induttivo r = x % y; // y > r >= 0 sempre vero ret = mcd(y, r); } return ret; } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 24 . . . Massimo Comun Divisore . . . public static void testMCD() { System.out.println("mcd(24,18) = “ + mcd(24,18)); System.out.println("mcd(132,48) = “ + } mcd(132,48)); System.out.println("mcd(7,3) = “ + mcd(7,3)); System.out.println("mcd(1,1) = “ + mcd(1,1)); System.out.println("mcd(4,1) = “ + mcd(4,1)); System.out.println("mcd(12,8) = “ + mcd(12,8)); public static void main(String[] args) { testMCD(); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 25 . . . Massimo Comun Divisore q Output del programma: mcd(24,18)=6 mcd(132,48)=12 mcd(7,3)=1 mcd(1,1)=1 mcd(4,1)=1 mcd(12,8)=4 http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 26 Elevamento a potenza. . . q Riprendiamo la definizione ricorsiva della funzione potenza tra 2 interi non negativi: 1 se e = 0 potenza (b,e) = prodotto(b,potenza(b,e - 1)) public static int potenza(int b, int e) { int p; if (e == 0) p = 1; // se e = 0 else p = prodotto(b, potenza(b, e-1))); return p; } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione se e > 0 // se e > 0 27 . . . Elevamento a potenza. . . q Vediamo una definizione ricorsiva alternativa per la funzione potenza tra 2 interi non negativi: 1 b se e = 0 se e = 1 power(b,e/2)) * power(b,e/2)) b * power(b,e/2)) * power(b,e/2)) se e è pari se e è dispari power (b,e) = http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 28 . . . Elevamento a potenza. . . public static int power(int b, int e){ int res; //casi base if (e==0) res = 1; // primo caso base else if (e==1) res = b; // secondo caso base else if (e%2==0) // primo caso induttivo res = power(b,e/2)*power(b,e/2); else // secondo caso induttivo res = b*power(b,e/2)*power(b,e/2); return res; } // potrei ottimizzare ancora il codice ? http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 29 . . . Elevamento a potenza class Potenza{ public static void main(String[] args) { testPower(); // Esempio di applicazione di test } public static void testPower(){ System.out.println("metodo ricorsivo"); System.out.println(power(2,0)+ " = 1"); System.out.println(power(2,1)+ " = 2"); System.out.println(power(2,3)+ " = 8"); System.out.println(power(2,4)+ " = 16"); System.out.println(power(2,9)+ " = 512"); System.out.println(power(2,10)+ "=1024"); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 30 Stringa palindroma . . . q Riprendiamo la definizione di stringa palindroma: una stringa che coincide con la stringa stessa letta da destra verso sinistra q Caratterizzazione induttiva: § la stringa vuota è palindroma – passo base § una stringa costituita da un singolo carattere è palindroma – passo base § una stringa c s d è palidroma, se s è una stringa palidroma e c ed d sono due caratteri uguali – passo induttivo § nient'altro è una stringa palindroma http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 31 . . . Stringa palindroma . . . q Problema: Si vuole determinare se una data stringa è palindroma o no. q Dati di ingresso: § Un oggetto s di tipo String q Pre-condizioni: § Oggetto s != null q Dati di uscita: § true se la stringa è palindroma http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 32 . . . Stringa palindroma . . . q Implementazione dell’algoritmo e metodi di test: class StringaPalindroma { public static void main(String[] args) { testPalindroma(); } public static boolean palindroma(String s) { // Determina se una stringa non nulla // in ingresso e' palindroma o no. boolean pal; if (s.length() <= 1) // i due casi base pal = true; else // caso induttivo pal = (s.charAt(0)==s.charAt(s.length()-1)) && palindroma(s.substring(1,s.length()-1)); return pal; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 33 . . . Stringa palindroma . . . public static void testPalindroma() { String s = new String(""); // stringa vuota palindroma System.out.println("'"+s+"' palindroma? "+palindroma(s)); s = new String("z"); // stringa di 1 solo carattere System.out.println("'"+s+"' palindroma? "+palindroma(s)); s = new String("abba"); // s palindroma System.out.println("'"+s+"' palindroma? "+palindroma(s)); s = new String(“amaroma"); // s non palindroma System.out.println("'"+s+"' palindroma? "+palindroma(s)); s = new String(“amoroma"); // s palindroma System.out.println("'"+s+"' palindroma? "+palindroma(s)); s = new String(“itopinonavevanonipoti"); // s palindroma System.out.println("'"+s+"' palindroma? "+palindroma(s)); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 34 . . . Stringa palindroma q Output del programma: “” palindroma? true “z” palindroma? true “abba” palindroma? true “amaroma” palindroma? false “amoroma” palindroma? true “itopinonavevanonipoti” palindroma? true C:> http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 35 Ricorsione su array q Gli array sono sequenze di elementi (così come ad esempio le stringhe) ma diversamente dalle stringhe non sono un tipo ricorsivo q Gli indici di un array sono numeri naturali e come tali sono un tipo ricorsivo q La ricorsione su array è possibile come ricorsione sugli indici dei suoi elementi Vediamo un esempio http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 36 Sequenza simmetrica di interi . . . q Una sequenza di numeri interi tutti positivi tranne che per uno 0 in posizione centrale si dice simmetrica se la sequenza stessa coincide con la sequenza in ordine inverso q Caratterizzazione ricorsiva: § la sequenza costituita solo da uno 0 è simmetrica (passo base) § una sequenza n s m è simmetrica, se s è simmetrica e n ed m sono due numeri interi positivi uguali (passo induttivo) § nient'altro è una sequenza simmetrica http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 37 . . . Sequenza simmetrica di interi . . . q Problema: Si vuole determinare se una data sequenza di numeri è simmetrica o no. q Dati di ingresso: § Un array non vuoto di n numeri interi q Pre-condizioni: § Dimensione n dell’array > 0 e dispari § Elementi array interi positivi a[i] > 0 § Elemento centrale nullo a[n/2] = 0 q Dati di uscita: § true se la sequenza è simmetrica http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 38 . . . Sequenza simmetrica di interi . . . public class SequenzaInteriSimmetrica { public static void main(String[] args) { testSimmetrica(); } public static boolean simmetrica(int[] v) { return simmetrica(v, 0, v.length-1); } private static boolean simmetrica(int[] v, int i, int j) { boolean sim; if (i > j) sim = false; // fine array else if (v[i] == 0) sim = true; // in mezzo all’array else sim = (v[i] == v[j]) && simmetrica(v, i+1, j-1); return sim; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 39 . . . Sequenza simmetrica di interi . . . public static void testSimmetrica() { int[] v = new int[7]; v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 0; v[4] = 3; v[5] = 2; v[6] = 1; System.out.println(simmetrica(v)); v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 0; v[4] = 1; v[5] = 2; v[6] = 3; System.out.println(simmetrica(v)); v = new int[1]; v[0] = 0; System.out.println(simmetrica(v)); v = new int[3]; v[0] = 3; v[1] = 0; v[2] = 4; System.out.println(simmetrica(v)); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 40 . . . Sequenza simmetrica di interi q Output del programma: true false true false C:> http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 41 Lunghezza sottostringa . . . q Definire un metodo ricorsivo che, presi come parametri una stringa s ed un carattere c, restituisca la lunghezza della più lunga sequenza di caratteri c consecutivi in s. q Esempio: § s = “tprottatttchttttetttx” § c = ‘t’ § output = 4 http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 42 . . . Lunghezza sottostringa . . . q Problema: trovare ricorsivamente in una stringa s la lunghezza della più lunga sottosequenza di caratteri c q Dati di ingresso: § String s e carattere c q Pre-condizioni: § s != null q Dati di uscita: § La lunghezza della sottosequenza più lunga di caratteri c in s http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 43 . . . Lunghezza sottostringa . . . public class SottoStringaMax { public static void main(String[] args) { testSottoSeqRic(); } public static int sottoSeqRic(String s, char c) { return sottoSeqRic(s, c, 0); } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 44 . . . Lunghezza sottostringa . . . private static int sottoSeqRic(String s,char c,int nc){ int lun; if (s.length() == 0) lun = nc; else if (s.charAt(0) == c) { nc++; lun = sottoSeqRic(s.substring(1), c, nc); if (lun < nc) lun = nc; } else { // s.charAt(0) != c lun = sottoSeqRic(s.substring(1), c, 0); if (lun < nc) lun = nc; } return lun; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 45 . . . Lunghezza sottostringa . . . public static void testSottoSeqRic() { String s = "tprottatttchttttetttx"; char c = 't'; int max = sottoSeqRic(s, c); System.out.println("max lung sottoseq ch "+ c+" in "+s+": "+max); s = "tt"; c = 't'; max = sottoSeqRic(s, c); System.out.println("max lung sottoseq ch "+ c+" in "+s+": "+max); s = ""; c = 't'; max = sottoSeqRic(s, c); System.out.println("max lung sottoseq ch "+ c+" in "+s+": "+max); s = "abc"; c = 't'; max = sottoSeqRic(s, c); System.out.println("max lung sottoseq ch"+ c+" in "+s+": "+max); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 46 . . . Lunghezza sottostringa q Output del programma: max max max max lung lung lung lung sottoseq sottoseq sottoseq sottoseq ch ch ch ch t t t t in in in in tprottatttchttttetttx: 4 tt: 2 : 0 abc: 0 C:> http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 47 Fibonacci . . . q Ricordiamo la definizione del numero di Fibonacci n: 0, se n = 0 – p.b. F (n) = 1, se n = 1 – p.b. F(n-2) + F(n-1) se n > 1 – p.i. q Sequenza di Fibonacci: F(0), F(1), F(2), ... cioè: 0, 1, 1, 2, 3, 5, 8, 13, 21 http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 48 . . . Fibonacci . . . q Una implementazione ricorsiva di Fibonacci farà uso di ricorsione multipla: § Il metodo può causare più di una attivazione ricorsiva dello stesso metodo F(n) F(n-1) F(n-2) http://www.dia.uniroma3.it/~java/fondinf/ F(n-2) F(n-3) F(n-3) Esercizi Ricorsione F(n-4) 49 . . . Fibonacci . . . q Problema: dato un interno n si vuole calcolare ricorsivamente la funzione fibonacci e il numero di attivazioni del metodo per il relativo calcolo q Dati di ingresso: § Un intero n q Pre-condizioni: § n ≥ 0 q Dati di uscita: § Fibonacci di n § Numero di attivazioni http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 50 . . . Fibonacci . . . public class Fibonacci { int natt; Fibonacci() { } public long numeroAttivazioni() { return natt; } public static void main(String[] args) { testFibonacci(); } public long fibonacci(long n) { natt = 0; return fibo(n); } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 51 . . . Fibonacci . . . private long fibo(long n) { System.out.println("In fibo("+n+")"); natt++; long fib; if (n == 0) { System.out.println("Finito"); fib = 0; } else if (n == 1) { System.out.println("Finito"); fib = 1; } else { System.out.println("Attivazione di fibo("+(n-1)+")"); fib = fibo(n-1); System.out.println("Attivazione di fibo("+(n-2)+")"); fib += fibo(n-2); System.out.println("Termine di fibo("+n+")"); } return fib; } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 52 . . . Fibonacci . . . public static void testFibonacci() { Fibonacci fib = new Fibonacci(); System.out.println("fib 8 = "+fib.fibonacci(8)); System.out.println("attivazioni fib 8 = "+ fib.numeroAttivazioni()); System.out.println("fib 2 = "+ fib.fibonacci(2)); System.out.println("attivazioni fib 2 = "+ fib.numeroAttivazioni()); System.out.println("fib 1 = "+fib.fibonacci(1)); System.out.println("attivazioni fib 1 = "+ fib.numeroAttivazioni()); System.out.println("fib 0 = "+fib.fibonacci(0)); System.out.println("attivazioni fib 0 = "+ fib.numeroAttivazioni()); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 53 . . . Fibonacci . . . q Output del programma: In fibo(4) Attivazione di fibo(3) In fibo(3) Attivazione di fibo(2) In fibo(2) Attivazione di fibo(1) In fibo(1) Finito Attivazione di fibo(0) In fibo(0) Finito Termine di fibo(2) (. . . segue . . .) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 54 . . . Fibonacci . . . Attivazione di fibo(1) In fibo(1) Finito Termine di fibo(3) Attivazione di fibo(2) In fibo(2) Attivazione di fibo(1) In fibo(1) Finito Attivazione di fibo(0) In fibo (0) Finito Termine di fibo(2) Termine di fibo(4) (. . . segue . . .) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 55 . . . Fibonacci fib 4 = 3 attivazioni fib 4 = 9 In fibo(1) Finito fib 1 = 1 attivazioni fib 1 = 1 In fibo(0) Finito fib 0 = 0 attivazioni fib 0 = 1 C:> http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 56 Torri di Hanoi . . . q Ricordiamo il problema delle Torri di Hanoi: spostare una torre di dischi seguendo le seguenti regole: 1. inizialmente, la torre di dischi di dimensione decrescente è posizionata su un perno 1; 2. l'obiettivo è quello di spostare la torre su un perno 2, usando un perno 3 come appoggio; http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 57 . . . Torri di Hanoi . . . 3. le condizioni per effettuare gli spostamenti sono: 1. è possibile spostare un solo disco alla volta, dalla cima di una torre alla cima di un'altra torre; 2. tutti i dischi, tranne quello che viene spostato, devono stare su una delle torri 3. un disco non può mai stare su un disco più piccolo http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 58 . . . Torri di Hanoi . . . q Problema: spostare una torre di n dischi dal perno 1 al perno 2 seguendo le regole suddette q Dati di ingresso: § Numero n di dischi da spostare; perno iniziale e perno destinazione q Pre-condizioni: § n > 1 q Post-condizioni: § La sequenza di spostamenti rispetta le regole q Dati di uscita: § Sequenza di spostamenti dei singoli dischi http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 59 . . . Torri di Hanoi . . . public class Hanoi { private static void muoviUnDisco(int sorg, int dest) { System.out.println("muovi un disco da "+sorg+" a "+dest); } private static void muovi(int n, int sorg, int dest, int aux){ if (n == 1) muoviUnDisco(sorg, dest); else { muovi(n-1, sorg, aux, dest); muoviUnDisco(sorg, dest); muovi(n-1, aux, dest, sorg); } } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 60 . . . Torri di Hanoi . . . . . . public static void testHanoi() { /* muovere n dischi da 1 a 2 * con 3 come appoggio */ int n = 3; System.out.println(“n = “ + n); muovi(n, 1, 2, 3); n = 1; System.out.println(“n = “ + n); muovi(n, 1, 2, 3); n = 10; System.out.println(“n = “ + n); muovi(n, 1, 2, 3); } public static void main(String[] args) { testHanoi(); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 61 . . . Torri di Hanoi q Output del programma: n = 3 muovi un muovi un muovi un muovi un muovi un muovi un muovi un n = 1 muovi un n = 10 disco disco disco disco disco disco disco da da da da da da da 1 1 2 1 3 3 1 a a a a a a a 2 3 3 2 1 2 2 disco da 1 a 2 (seguono 1023 mosse) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 62 Visualizzazione Torri di Hanoi . . . q Per esercizio vogliamo visualizzare lo stato dei perni ad ogni spostamento di dischi q Sfruttiamo l’esercizio visualizza triangolo di asterischi visto nella dispensa 11 “Istruzioni ripetitive” del secondo quarto q Nota: nel programma precedente lo stato attuale dei dischi è “memorizzato” nella pila delle attivazioni perciò è impossibile accedervi interamente in ogni istante http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 63 . . . Visualizzazione Torri di Hanoi . . . public class Hanoi { int[][] perni; // memorizza lo stato attuale dei perni int num_dischi; Hanoi(int n) { perni = new int[n][3]; num_dischi = n; for (int i = 0; i < n; i++) perni[i][0] = n-i; stampa(); } private void muoviUnDisco(int sorg, int dest) { System.out.println("muovi un disco da "+sorg+" a "+dest); int i, j; for (i=num_dischi-1;(i>0) &&(perni[i][sorg-1]==0);i--); for (j=num_dischi-1;(j>=0)&&(perni[j][dest-1]==0);j--); . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 64 . . . Visualizzazione Torri di Hanoi . . . } perni[++j][dest-1] = perni[i][sorg-1]; perni[i][sorg-1] = 0; stampa(); public void stampa() { for(int i = num_dischi-1; i >= 0; i--) { for(int j = 0; j < 3; j++) { int l = perni[i][j]; for(int k = 0; k < num_dischi-l; k++) System.out.print(" "); for(int k = 0; k < l*2; k++) System.out.print("*"); //stampa l*2 asterischi for(int k = 0; k < num_dischi-l; k++) System.out.print(" "); System.out.print(" "); } System.out.println(); } . . . segue . . . http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 65 . . . Visualizzazione Torri di Hanoi . . . } for(int k = 0; k < 4+num_dischi*6; k++) System.out.print("-"); System.out.println(); private void muovi(int n, int sorg, int dest, int aux) { . . . vedi codice precedente . . . } public static void testHanoi() { int n = 3; Hanoi hanoi = new Hanoi(n); hanoi.muovi(n, 1, 2, 3); } public static void main(String[] args) { testHanoi(); } } http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 66 . . . Visualizzazione Torri di Hanoi . . . q Output del programma per n=3: ** **** ****** ---------------------muovi un disco da 1 a 2 **** ****** ** ---------------------muovi un disco da 1 a 3 ****** ** **** ---------------------muovi un disco da 2 a 3 ** ****** **** ---------------------(. . . segue . . .) http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 67 . . . Visualizzazione Torri di Hanoi muovi un disco da 1 a 2 ** ****** **** ---------------------muovi un disco da 3 a 1 ** ****** **** ---------------------muovi un disco da 3 a 2 **** ** ****** ---------------------muovi un disco da 1 a 2 ** **** ****** ---------------------C:> http://www.dia.uniroma3.it/~java/fondinf/ Esercizi Ricorsione 68