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