n > 1 - Dipartimento di Informatica e Automazione

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