Ricorsione
Strumento potente per definizioni
matematiche
Possibilità di definire insieme infinito di
oggetti con regola finita
possibilità di descrivere un insieme infinito di
computazioni con un programma finito
Ricorsione in matematica
Le formule matematiche sono spesso
espresse in termini ricorsivi
Esempio: definizione di fattoriale
1!=1
N!=N * (N-1)!
Metodi ricorsivi
Contengono riferimenti espliciti a sé stessi
direttamente ricorsivi
Un metodo ne invoca un altro e
l’esecuzione di quest’ultimo porta ad un
certo punto ad invocare nuovamente
(direttamente o indirettamente) il metodo
originale
indirettamente ricorsivi
Ricorsione infinita
Requisito fondamentale:
chiamata ricorsiva subordinata ad una condizione che
ad un certo istante deve divenire non soddisfatta
Qualsiasi definizione ricorsiva deve avere
una parte non ricorsiva, detta base della
ricorsione, che permette alla ricorsione
stessa di terminare
Nell’esempio precedente del fattoriale la
base è 1! che è posto uguale ad 1
Variabili in metodi ricorsivi
Ogni invocazione genera un nuovo
insieme di variabili locali
Ogni parametro riceve un valore iniziale in
base alla nuova invocazione
Ogni volta che il metodo termina si ritorna
al metodo che lo ha chiamato ( che
potrebbe essere lo stesso)
Numeri di Fibonacci
Schema più complicato di composizione
ricorsiva che potrebbe (e dovrebbe)
essere tradotto in forma iterativa
Definizione:
fib0 = 0
fib1 = 1
fibn+1 = fibn + fibn-1
Implementazione ricorsiva
int computeFib(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
return computeFib(n-1)+computeFib(n2);
}
Numero di invocazioni
5
4
3
2
3
2
1
1
2
1
1
0
0
Numero totale di invocazioni cresce
esponenzialmente
1
0
Implementazione iterativa
int computeFib(int n)
{
int i = 1, x = 1, y = 0;
while (i < n) {
i = i+1;
x = x+ y;
y = x -y;
}
return x;
}
Considerazioni
Ricorsione deve essere evitata se esiste
una soluzione iterativa ovvia
Non vuol dire evitare la ricorsione a
qualunque costo
esistono molte buone applicazioni della
ricorsione
algoritmi per loro natura ricorsivi vanno
implementati con metodi ricorsivi
Le torri di Hanoi
inventato nel 1880 da Lucas
Tre aste (o torri) ed n dischi di dimensioni diverse
(con buco per inserirli nelle aste)
All’inizio tutti i dischi sono nell’asta 1
in ordine decrescente di grandezza
Obiettivo: portarli nella torre 3 rispettando le
regole seguenti
nessun disco mai sopra uno più piccolo
si può spostare un solo disco alla volta
dischi sempre collocati su una torre (non a parte)
solo disco in cima ad una torre può essere spostato
Algoritmo ricorsivo
Obiettivo: spostare k dischi da torre 1 a torre 3
Algoritmo:
Spostare k-1 dischi da torre originale a torre
temporanea
Spostare 1 disco da torre originale a torre di
destinazione
Spostare k-1 dischi da torre temporanea
a torre di destinazione
Implementazione 1
void moveTowers(int k, int o,int d)
{
if (k > 0)
{
moveTowers(k-1, o, 6-o-d);
System.out.println("Sposta da "+o+"a"+d);
moveTowers(k-1,6-o-d,d);
}
}