Sei sulla pagina 1di 22

Corso di Fondamenti di Informatica

La ricorsione

La ricorsione

Si dice che un oggetto (una struttura dati, una funzione matematica, un


concetto) ricorsivo se possibile darne una definizione in termini di (varianti
di) s stesso

Esempio: la funzione matematica fattoriale


n!=n*(n-1)! Se n1
0!=1

Esempio: la definizione di sequenza


Una sequenza la sequenza vuota oppure un elemento seguito da una
sequenza:
s x1 U s
s x2 U s
s x3 U s
.
.
sn <>

La ricorsione

Esempio: una filastrocca per bambini


C'era una volta un re seduto sul sof che disse alla sua serva raccontami una
storia e la serva incominci: C'era una volta un re...

Esempio: in natura

Il Principio dell'induzione

Il principio d'induzione un enunciato sui numeri naturali che in matematica trova


un ampio impiego nelle dimostrazioni:

In pratica:
si dimostra che vale P(1) (o P(0)), cio che la propriet P vale per 1(o 0).
si assume come ipotesi che l'asserto P(n) valga per un generico n e da tale
assunzione si dimostra che vale anche P(n + 1)

Il Principio dell'induzione: un Esempio

Dimostriamo che vale l'asserto:

3 . .

1
2

Vogliamo quindi dimostrare la seguente propriet P

3 . .

1
2

Base dell'induzione: l'asserto vero per n=1:


Passo induttivo:

Il Principio dell'induzione: un Esempio


Passo induttivo:

Possiamo facilmente asserire che

3 . .

Da ci, in pochi passi, facile dimostrare l'asserto:

1
2

La Ricorsione

In programmazione la ricorsione una tecnica potente che:


permette di suddividere un problema da risolvere in sottoproblemi simili a quello
originale

la potenza della ricorsione nasce dalla possibilit di definire un insieme infinito di


oggetti con regola finita

allo stesso modo, un insieme infinito di computazioni pu essere descritto con


un programma ricorsivo finito.

La ricorsione si applica ad algoritmi ricorsivi (i quali a loro volta sono spesso


basati su strutture dati ricorsive)

Per tali algoritmi la tecnica ricorsiva permette di scrivere programmi eleganti e


sintetici, sar tuttavia opportuno verificarne di volta in volta l'efficienza rispetto ad
altri tipi di soluzioni

Il programma fattoriale

La versione ricorsiva del fattoriale :


int fatt(int x){
int f;
if (x<=1) f=1;
else f=x*fatt(x1);
return f;
}

passo BASE

Passo INDUTTIVO

Mentre quella iterativa :


int fatt(const int x){
int f=1,i;
for(i=1;i<=x;i++)
f=f*i;
return f;
}

Lo schema degli algoritmi ricorsivi

Un algoritmo ricorsivo sempre codificato per mezzo di un programma che


richiama se stesso:

P (T1 x) {
...
if (p(x)) F;
else C(S,P);
R
}

int fatt(int x){


int f;
if (x<=1) f=1;
else f=x*fatt(x1);
return f;
}

Il predicato p(x) verifica il


caso BASE

Terminazione

La chiamata ricorsiva deve quindi essere subordinata ad una condizione che ad


un certo istante risulti soddisfatta (il predicato p).

Il numero di chiamate necessarie viene detto profondit della ricorsione

10

Algoritmi ricorsivi

Esistono diversi tipi di algoritmi ricorsivi:


Si parla di mutua ricorsione quando nell'algoritmo una funzione ne richiama
un'altra che a sua volta richiama la prima, altrimenti si parla di ricorsione
diretta
Si parla di ricorsionelineare quando vi solo una chiamata ricorsiva
all'interno della funzione, e di ricorsione non lineare nel caso in cui le
chiamate ricorsive siano pi di una.
La distinzione pi importante ai fini pratici si ha fra ricorsione di coda (tail
recursion) e ricorsione non di coda. Si parla di ricorsione di coda quando la
chiamata ricorsiva l'ultima istruzione eseguita nella funzione. Questo tipo di
algoritmo ricorsivo possibile trasformarlo semplicemente in una versione
iterativa, che di solito pi efficiente,

11

Meccanismo interno di ricorsione

Un sottoprogramma ricorsivo dunque un sottoprogramma che richiama


direttamente o indirettamente se stesso

Non tutti i linguaggi realizzano il meccanismo della ricorsione. Quelli che lo


realizzano possono utilizzare due tecniche:
gestione LIFO di pi copie della stessa funzione, ciascuna con il proprio
insieme di variabili locali
Gestione mediante record di attivazione; un unica copia del codice del
sottoprogramma ma ad ogni chiamata associato un record di attivazione
(variabili locali e punto di ritorno). In questo caso diversi record di attivazione
dello stesso sottoprogramma possono essere contemporaneamente presenti
nello stack

12

Schema ricorsivo
Fase ascendente
Fase discenden te

m ain
...
...
..fat t(3)
6

fat t (3)

fat t (2)

fat t (1)

if (x< = 1)
f= 1;
else
f= x* fat t (x-1);

if (x< = 1)
f= 1;
else
f= x* fat t (x-1);

if (x< = 1)
f= 1;
else
f= x* fat t (x-1);

ret urn f;

ret urn f;

ret urn f;

Dalla forma ricorsiva a quella iterativa


Un problema ricorsivo pu sempre essere risolto in termini iterativi (il viceversa
non vero).
Nel caso in cui la ricorsione in coda, la trasformazione molto semplice. Ad
esempio:
P (T1 x) {
...
if p(x) F;
else {S;P(x);}
return
}

while !p(x)
S;
F;

Quando invece la ricorsione non l'ultima istruzione della procedura si pu


optare per una soluzione che preveda l'utilizzo di uno stack di supporto che
permette di salvare i valori delle chiamate ricorsive e tramite un ciclo while
simulare ci che fa lo stack di sistema.

Francesco Fontanella, Corso di Fondamenti di Informatica II


a.a. 2009/2010

Dalla forma ricorsiva a quella iterativa: il fattoriale

Forma ricorsiva

int fatt(const int x){


int f;
i f (x<=1) f=1;
else f=x*fatt(x-1);
return f ;
}

Forma iterativa

int fatt(const int x){


i nt f =1, i ;
f or ( i =1; i < =x ; i ++)
f=f*i;
retu rn f ;
}

Alcuni esempi

Esponenziale

Calcolo lunghezza di un stringa

Ricerca del minimo.

Ricerca di un valore

Stringa palindrome

Inversione di un stringa

Esponenziale
float exp( float x, int n)
{
if (n == 1)
return x;
else return x*exp(n1);
}

ricorsione in coda

NOTA
Questa versione tiene conto solo di esponenti positivi. Provare a scrivere la
stessa funzione (ricorsiva) tenendo conto anche del caso n < 0

Calcolo Lunghezza di una Stringa


void strlen( char *str)
{
if (str[0] == '\0')
return 0;
else return 1 + strlen(&str[1]);

Posso anche scrivere:


*str == '\0'

ricorsione in coda

Funzione di Ricerca del Minimo ricorsiva


int ric_min( int n, int v[])
{
int m;
if (n==1)
return v[0];
m = ric_min(n1, &v[1]);
if (m < v[0])
return m;
else return v[0];
}

NOTA
Questo un caso di ricorsione non in coda

Funzione di Ricerca di valore ricorsiva

bool check_val( int n, int v[], int val)


{
if (v[0] == val)
return true;
else
if (n > 1)
return check_val(n1, v+1, val);
}

Uso dell'aritmetica
dei puntatori

Palindrome

Stringa palindrome:
uguale se letta nei due versi: anna, radar, asorrosa, abbbcbbba

Una stringa palindrome se:


ha un solo carattere, oppure
composta da un primo ed ultimo carattere uguali che racchiudono una
stringa ancora palindrome

Palindrome
bool palindrome(char str[], int first, int last)
{
if (str[last] == str[first]){
if ((last first) <= 1)
return true;
else return palindrome(str, first+1, last1);
} else return false;
}

NOTA
Provare a scrivere la versione iterativa

Potrebbero piacerti anche