Ricorsione
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 1/1
Ricorsione
• Un metodo ricorsivo è un metodo che direttamente o
indirettamente richiama se stesso.
• Una definizione ricorsiva è autoreferenziale e definisce un
metodo in termini di istanze più semplici dello stesso problema:
1. si definisce come risolvere problemi analoghi a quello di
partenza, ma che hanno dimensione ridotta e possono
essere risolti in maniera estremamente semplice (detti casi
base);
2. quindi si definisce come ottenere la soluzione del problema
di partenza combinando la soluzione di uno o più problemi
analoghi.
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 2/1
Ricorsione - Induzione
La ricorsione è basata sul principio di induzione matematica:
• se un asserto P vale per n = n0 (caso base)
• e si può provare che, assumendola valida per n, allora vale per
n + 1 (passo induttivo)
• allora P vale per ogni n ≥ n0
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 3/1
Ricorsione - Induzione
Per dimostrare che un asserto P (n) dove n ∈ N vale per ogni n ∈ N
possiamo utilizzare il principio di induzione come segue:
Poniamo U = n ∈ N vale P (n)
• Si dimostra che vale P (0), con 0 ∈ U vale P (n)
• Si assume come ipotesi che l’asserto P (n) valga per un generico
n∈U
• Si dimostra che P (n) vale anche per P (n + 1), ovvero
n∈U →n+1∈U
• Si conclude che l’insieme U dei numeri n per cui vale P (n)
coincide con N
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 4/1
Ricorsione - Induzione
Un tipico esempio di induzione è dato dalla formula di Gauss
n
n(n+1)
i
=
i=1
2
Dimostriamo che vale l’asserto ∀n ∈ N : 0 + 1 + 2 + 3 + ... + n =
Quindi P (n)
≡
0 + 1 + 2 + 3 + ... + n =
n(n+1)
2
n(n+1)
2
Caso base : dimostriamo che P (n) vale per n = 0
0=
0·1
2
Passo induttivo : dimostriamo che P (n) ⇒ P (n + 1)
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 5/1
Ricorsione - Fattoriale
Un ulteriore esempio di ricorsione è dato dal fattoriale di un numero
intero.
Immaginiamo di dover calcolare il fattoriale di un numero n:
n! = n ∗ (n − 1) ∗ ... ∗ 3 ∗ 2 ∗ 1
Si ricordi che 0! = 1 e che il fattoriale non è definito per i numeri
negativi.
Come possiamo definire un algoritmo che calcoli la funzione fattoriale?
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 6/1
Ricorsione - Fattoriale
Osserviamo che:
n! = n ∗ (n − 1) ∗ (n − 2) ∗ ... ∗ 2 ∗ 1 = n ∗ (n − 1)!
La versione ricorsiva sarà:
0! = 1
(caso base, per n = 0)
n! = n ∗ (n − 1)!
(se n > 0)
f (x) =
⎧
⎨1
x=0
⎩ x ∗ f (x − 1) x > 0
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 7/1
Ricorsione - Fattoriale
int factorial (int n)
{
int result;
if (n<0) result = -1;
// Fattoriale non calcolabile
else if (n == 0)
result = 1;
// 0! = 1 (caso base)
else result = n * factorial(n-1); // ricorsione
return (result);
}
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 8/1
Ricorsione - Fattoriale
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 9/1
Ricorsione - Fattoriale
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 10/1
Ricorsione Tail - Ricerca in vettore
Esercizio: cercare un elemento in un vettore di interi in modo ricorsivo.
Procedimento:
• Verificare l’eguaglianza tra il valore da cercare e il primo
elemento del vettore: se l’eguaglianza è verificata, terminare
restituendo la posizione dell’elemento nel vettore
• Se l’eguaglianza non è verificata, ripetere il passo precedente
verificando l’eguaglianza tra il valore e l’elemento successivo
• Se l’eguaglianza non è verificata per alcun elemento del vettore,
terminare restituendo -1
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 11/1
Ricorsione Tail - Ricerca in vettore
#include <stdio.h>
int ricerca (int array[], int x, int a, int lenght)
{
if (x == array[a]) return a;
if (a < lenght) return ricerca (array, x, a+1, lenght);
return (-1);
}
int main(void) {
int DIM; printf ("Dimensione vettore? "); scanf("%d",&DIM);
int x; int lista[DIM]; int i; int lenght=DIM; int pos;
for (i=0; i<DIM; i++) {
printf ("Valore di posto %d: ",i); scanf ("%d",&lista[i]);}
printf ("\nValore da cercare: "); scanf ("%d",&x);
pos = ricerca (lista, x, 0, lenght-1);
if (pos == -1) printf ("\nValore non trovato");
else printf ("\nValore trovato in posto %d", pos);
return (0);
}
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 12/1
Ricorsione - Considerazioni
Non tutti gli algoritmi possono essere espressi in forma ricorsiva:
esistono alcuni requisiti fondamentali affinché un algoritmo sia
esprimibile in forma ricorsiva.
• Il primo è la possibilità di formulare l’algoritmo in funzione di se
stesso
• Il secondo è che non si verifichi mai un ciclo infinito: deve
esistere una condizione di terminazione, ovvero almeno una
istanza del processo che non richiede di essere scomposta in
ulteriori istanze più semplici.
Nell’algoritmo del fattoriale è rappresentata da 1! o da 0!.
Inoltre non deve esistere un valore di ingresso che renda
impossibile la terminazione dell’esecuzione.
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 13/1
Ricorsione - Considerazioni
Un approccio iterativo richiede di considerare la soluzione del
problema unitariamente, mediante una sequenza di passi elementari;
Un approccio ricorsivo richiede di esprimere il problema in termini dello
stesso problema, decomposto in casi più semplici.
Deve essere identificato un caso base che non richiede tale
decomposizione, per consentire la terminazione.
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 14/1
Ricorsione - Vantaggi e svantaggi
Vantaggi ricorsione:
• Possibilità di risolvere problemi anche complessi con poche righe
di codice;
• Algoritmi facilmente interpretabili.
Svantaggi ricorsione:
• Talvolta eleganza e semplicità di una formulazione ricorsiva
possono impattare negativamente sulla efficienza (risorse
utilizzate, memoria utilizzata)
Informatica Generale - Ricorsione v1.0, aa 2005-2006 – p. 15/1