Sei sulla pagina 1di 20

Informatica A

Ricorsione

1
L’induzione matematica

• Si usa nelle definizioni e nelle


dimostrazioni
• Definizione induttiva:
definisco induttivamente i numeri pari
– 1) 0 è un numero pari
– 2) se n è un numero pari anche n+2 è un
numero pari
Iterazione e ricorsione
• Sono i due concetti informatici che
nascono dal concetto di induzione
• L’iterazione si realizza mediante la tecnica
del ciclo
• Il calcolo del fattoriale:
– 0! = 1
– n! = n (n - 1)(n - 2)…. 1 (realizzo un ciclo)

3
Fattoriale – versione iterativa
int fattoriale (int n) {
int i, f;
f = 1;
for (i = 1; i <= n; i = i + 1)
{
f = f * i;
} /* for */
return f;
} /* fattoriale */
4
Lo “spirito” del metodo ricorsivo
• Esiste un CASO BASE, che rappresenta un
sotto-problema facilmente risolvibile
• Esempio: se N=0, so N! in modo “immediato” (vale 1)
• Esiste un PASSO INDUTTIVO che ci riconduce
(prima o poi) al caso base
– Consiste nell’esprimere la soluzione al problema (su
dati di una “dimensione” generica) in termini di
operazioni semplici e della soluzione allo stesso
problema su dati “più piccoli” (che, per tali dati, si
suppone risolto per ipotesi)
• Esempio: per N generico esprimo N! in termini di N (è un
dato direttamente accessibile) moltiplicato per (è una
operazione semplice) il valore di (N-1)! (che so calcolare per
ipotesi induttiva) N!=N(N-1)!

5
Fattoriale – versione ricorsiva
• 1) n! = 1 se n = 0
• 2) n! = n * (n - 1)! se n > 0
– riduce il calcolo a un calcolo più semplice
– ha senso perché si basa sempre sul fattoriale
del numero più piccolo, che io conosco
– ha senso perché si arriva a un punto in cui
non è più necessario riusare la def. 2) e
invece si usa la 1)
– 1) è il caso base, 2) è il passo induttivo

6
Formulazione ricorsiva

int FattRic (int n) {


if (n == 0)
return 1;
else
return n * FattRic(n–1);
}

7
Ma…
• E ogni volta la funzione richiama se
stessa… il processo non continua
all’infinito?
• Quando si può dire che una ricorsione è
ben definita?
• Informalmente:
– Se ogni volta che si applica il passo indutivo
ci si avvicina in modo significativo allla
situazione riconosciuta come caso base,
allora la definizione non è circolare

8
Simulazione del calcolo
Invocazione di: FattRic(3)
3 = 0? No
Þ calcola fattoriale di 2 e moltiplica per 3
2 = 0? No
Þ calcola fattoriale di 1 e moltiplica per 2
1 = 0? No
Þ calcola fattoriale di 0 e moltiplica per 1
0 = 0? Si
Þ fattoriale di 0 è 1
Þ fattoriale di 1 è 1 per fattoriale di 0, cioè 1 ´ 1 = 1
Þ fattoriale di 2 è 2 per fattoriale di 1, cioè 2

9
Formulazione ricorsiva
Main: r=FattR(3)
int FattR (int n) {
if (n == 0)

else
return 1;
3*2
}
return n * FattR(n–1);
FattR(3):3*FattR(2)
2*1
FattR(2):2*FattR(1)
1*1
FattR(1):1*FattR(0)
1
FattR(0):1

10
Funzione esponenziale (intera)
• Iterativo: Iterativo:
int esp (int x, int y) {
1) x^y = 1 se y = 0 int i, e = 1;
for ( i = 1; i <= y; i++ )
2) x^y = x * x * … x e = e * x;
(y volte) se y > 0 return e;
}

• Ricorsivo: Ricorsivo:
int esp (int x, int y) {
1) x^y = 1 se y = 0 if (y == 0)
return 1;
2) x^y = x * x^(y-1) else
se y > 0 return x * esp(x, y-1);
}

11
Esecuzione di sottoprogrammi
ricorsivi
• In un certo istante possono essere in
corso diverse attivazioni dello stesso
sottoprogramma
• Ogni attivazione esegue lo stesso codice
ma opera su copie distinte dei parametri
e delle variabili locali

12
int FattRic(int); Il modello a runtime:
main(){
int val, ris; esempio
printf("dammi un naturale "); val = 3
scanf("%d", &val); ris = 6
ris = FattRic(val); n=3
printf("\nfattoriale= %d", ris); temp = 3* 2
}; n=2
int FattRic (int n) { temp = 2* 1
int temp; n=1
if (n == 0) temp = 1* 1
return 1; n=0
else { temp = ?
temp = n * FattRic(n-1);
return temp;
}
} temp: cella temporanea per
memorizzare il risultato della
assumiamo val = 3 funzione chiamata

13
Terminazione
• Attenzione al rischio di catene infinite di
chiamate
• Occorre che le chiamate siano soggette a
una condizione che prima o poi assicura
che la catena termini
• Occorre anche che l’argomento sia
“progressivamente ridotto” dal passo
induttivo, in modo da tendere prima o poi
al caso base

14
I numeri di Fibonacci
{1, 1, 2, 3, 5, 8, ….}
1) fib(n)=1 se n=0 opp. n=1 int fib(int n)
{if n==0 || n==1 return 1;
else return fib(n-1) +
2) fib(n)= fib(n-2);
fib(n-1) + fib(n-2) se }
n>1

Vengono usati per


modellare la crescita di
animali per diverse
generazioni
Dinamiche di popolazione
T0: **(1)
T1: ** (1)
T2: ** ** (2)
T3: ** ** ** (3)
T4: ** ** ** ** ** (5)
T5: ** ** ** ** ** ** ** ** (8)
T6: ** ** ** ** ** ** ** ** ** ** ** ** ** (13)
T7: ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
** ** ** ** ** ** (21) …etc.
Esempio: lunghezza stringhe
• Soluzione iterativa:
int lunghezzaI(char s[]) {
int l = 0;
while ( s[l] != '\0‘ )
l++;
return l;
}
• Soluzione ricorsiva:
int lunghezzaR(char *s) {
if (*s == '\0') return 0;
else return 1 + lunghezza(s+1);
}

17
Ricorsione o iterazione?
• Spesso le soluzioni ricorsive sono eleganti
• Sono vicine alla definizione del problema
• Però possono essere inefficienti
• Chiamare un sottoprogramma significa
allocare memoria a run-time

N.B. è sempre possibile trovare un


corrispondente iterativo di un
programma ricorsivo

18
MCD iterativo
int EuclideIter (int m, int n) {
while( m != n )
if ( m > n )
m = m – n;
else
n = n – m;
return m;
}

19
MCD – versione ricorsiva
int EuclideRic (int m, int n) {
if ( m == n )
return m;
else if ( m > n )
return EuclideRic(m-n, n);
else
return EuclideRic(m, n - m);
}

20

Potrebbero piacerti anche