Programmazione ricorsiva
Silvana Badaloni
Fondamenti di Informatica
A.A. 2004/05
February 28, 2005
ricorsione
• si puo’ definire un processo in termini di se stesso?
• si puo’ definire una funzione in termini di se stessa?
• la soluzione per un caso generico puo’ essere ricavata sulla base della soluzione di un altro caso,
generalmente piu’ semplice dello stesso problema
• S soluzione di un problema, applicata ai dati D, è
ricorsiva se é espressa:
- S(D0) = S0 caso base
- S(D) = f (S(D0)) per D <> D0 e D0 piu’ semplice
di D
• definizione ricorsiva è un modo naturale per descrivere i problemi e le loro soluzioni
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
1
definizioni ricorsive
• fattoriale iterativo: per ottenere n! moltiplicare
1 ∗ 2 ∗ 3 ∗ ... ∗ n
• fattoriale ricorsivo
– 1! = 1 passo base
– n! = n ∗ (n − 1)! passo ricorsivo
• la successione dei numeri di Fibonacci
F = {f0, f1, ..., fn}
– f0 = 0
– f1 = 1
– fn = fn−1 + fn−2
• potenza n-sima di xn = x ∗ x ∗ ... ∗ x
– x0 = 1
– xn = x ∗ xn−1
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
2
la ricorsione come strumento di programmazione
• molti linguaggi di programmazione permettono di
chiamare sottoprogrammi in maniera ricorsiva (e.g.
Pascal, C, C++, ect)
• permettono di tradurre direttamente le definizioni
matematiche ricorsive
• un altro modo di progettare gli algoritmi
• soluzioni chiare concise ed eleganti
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
3
la ricorsione in C
main() { ...
ricorsiva(<dati del problema>);
...
}
void ricorsiva(<parametri>) {...
if (<caso base>)
<tratta caso base>
else
ricorsiva(<dati ridotti>)
...
}
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
4
fattoriale
/*fattoriale ricorsivo */
#include <stdio.h>
long factorial(long);
main() {
int i;
for (i=1; i<=10; i++)
printf("2%d! = %ld\n", i, factorial(i));
return 0;
}
long factorial(long number)
{
if (number <= 1)
return 1;
else return (number * factorial(number - 1));
}
1! = 1
2! = 2
...
10! = 3628800
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
5
fibonacci ricorsivo
#include <stdio.h>
long fibonacci(long);
main() {
long result, number;
printf("inserisci un numero: ");
scanf("%ld", &number);
result = fibonacci(number);
printf("fibonacci(%ld) = %ld\n", number, result);
return 0;
}
long fibonacci(long n)
{
if (n == 0 || n==1)
return n;
else return (fibonacci(n-1) + fibonacci(n-2));
}
numero chiamate per calcolare l’n-simo numero di Fibonacci e’ 2n
200 numero di Fibonacci: 220 chiamate
- esplosione esponenziale di invocazioni
- complessità computazionale
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
6
ricorsione vs iterazione
struttura di controllo
selezione + ripetizione
controllo terminazione
caso base
ciclo infinito
aspetti negativi
oneroso peso delle chiamate
ripetizione
falsa condizione del ciclo
non rispecchia la natura d
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
7
ricerca binaria ricorsiva
algoritmo
se inizio e’ maggiore di fine \\
la ricerca fallisce
altrimenti
calcola la posizione C
se l’elemento in C e’ uguale a D la ricerca ha succe
altrimenti
se l’elemento in C e’ > D
ricerca tra inizio e C-1
altrimenti
ricerca tra C+1 e fine
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
8
ricerca binaria ricorsiva
#include <stdio.h>
#define N 5
int V[N]= {1, 6, 7, 13, 21};
int D;
int ricerca_binaria( int, int);
main() {
printf("inserire l’elemento");
scanf("%d", &D);
if (ricerca_binaria(0, N-1) ==1
printf("l’elemento %d e’ presente", D);
else
printf("l’elemento %d non e’ presente", D);
}
int ricerca_binaria(int inizio, int fine);
{ int C;
if (inizio > fine)
return 0;
else
C=(inizio+fine)/2;
if (D==V[C])
return 1;
else
if (D < V[C])
return ricerca_binaria(inizio, C-1);
else
return ricerca_binaria(C+1, fine);
} }
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
9
Divide and conquer
• divide: il problema è suddiviso in un certo numero
di sottoproblemi
• conquer: i sottoproblemi sono risolti ricorsivamente
• combine: le soluzioni dei sottoproblemi sono combinati per ottenere la soluzione del problema originale
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
10
strutture dati ricorsive 1
liste
Dato un insieme prefissato di elementi E:
• una lista può essere la lista vuota
• una lista non vuota può consistere di un primo
elemento detto testa e del resto della lista detta
coda;
struct elemento {
int inf;
struct elemento *pun;
};
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
11
strutture dati ricorsive 2
alberi
Dato un insieme prefissato di elementi E:
• un albero può essere vuoto
• un albero non vuoto può consistere di un solo elemento e ∈ E detto nodo
• un albero consiste di un nodo e ∈ E collegato
mediante archi diretti a un numero finito di altri
alberi
struct nodo {
int inf;
struct nodo *alb_sin;
struct nodo *alb_des;
};
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
12
LISP
• processa liste in modo ricorsivo
(a b c)
car0(a b c) − − > a
cdr0(a b c) − − > (b c)
• funzioni ricorsive
(defun factorial (n)
(cond ((eq n 0) 1)
(t (* n factorial (- n 1))))
S.Badaloni - Fond.Inf. 2004/05 - Programmazione ricorsiva
13