360 likes | 523 Views
Linguaggi di programmazione I La ricorsione. Prof. Luigi Di Lascio Lezione 10. Funzioni Ricorsive. 1 è un numero naturale Il successore di un numero naturale è un numero naturale.
E N D
Linguaggi di programmazione ILa ricorsione Prof. Luigi Di Lascio Lezione 10 LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Funzioni Ricorsive • 1 è un numero naturale • Il successore di un numero naturale è un numero naturale La definizione di un concetto matematico è detta ricorsivo se questo è definito (totalmente o parzialmente) in termini di se stesso In particolare: La definizione ricorsiva di una funzione utilizza la funzione stessa e una versione più semplice di questa LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Esempio: la definizione ricorsiva del fattoriale di n • 0!=1 • 2. n!=n*(n-1)! Se n=0 allora fat(n)=1 altrimenti fat(n)=n*fat(n-1) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
long int fat(int n){ long int fattoriale;if(n==0) fattoriale=1;elsefattoriale=n*fat(n-1); return fattoriale;} Esempio: la definizione ricorsiva del fattoriale di n, l’implementazione Se n=0 allora fat(n)=1 altrimenti fat(n)=n*fat(n-1) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Il proccesso ricorsivo LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Come evidenziare il processo ricorsivo long int fat(int m) { long int fattoriale; if(m==0) fattoriale=1; else fattoriale=m*fat(m-1); printf("fattoriale(%d) = %d\n",m,fattoriale); return fattoriale; } fattoriale(0) = 1 fattoriale(1) = 1 fattoriale(2) = 2 fattoriale(3) = 6 fattoriale(4) = 24 fattoriale(5) = 120 RIS. FINALE: fattoriale di 5 = 120 Premere un tasto per continuare . . . LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Definizioni ricorsive/1 Vita quotidiana (anzi serale e mangereccia) L’ordine di una o più pizze può essere cosi formulata: ordine := <pietanza> <conto> ordine : = <pietanza> <ordine> pietanza := margheritabruschetta vino conto := somma da pagare LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Definizioni ricorsive/2 Definizioni ricorsive di libro libro := <capitolo> libro: = <capitolo> <libro> <capitolo >:= qui definizione LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Definizioni ricorsive/3 Definizioni ricorsive di libro, capitolo e paragrafo libro := <capitolo> libro: = <capitolo> <libro> capitolo := <paragrafo> capitolo : = <paragrafo><capitolo> paragrafo : = <testo> paragrafo := <testo><paragrafo> testo := <parola> testo: = <parola><testo> parola:= una stringa presente sul vocabolario di italiano LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Definizioni ricorsive: in generale /1 Se questo è il caso più semplice, allora calcola la soluzione, altrimenti ridefinisce il problema usando la ricorsione Somma di n numeri interi Caso più semplice: la sequenza è costituita da un solo numero a[0]. In tal caso: somma = a[0] Parte ricorsiva: somma(n) = a[n-1]+somma(n-1) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
La funzione ricorsiva somma(n) long int somma(int a[], int dim) { if(dim==1) return a[dim-1]; else return (somma(a,dim-1)+a[dim-1]); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Definizioni ricorsive: in generale /2 Se C è il caso più semplice, allora calcola la soluzione immediata, altrimenti ridefinisci il problema mediante suoi sottoproblemi, usando la ricorsione Esempio: Definizione ricorsive di potenza di base b ed esponente intero positivo n: potenza(b,n) Se n=0 allora potenza(b, 0) = 1, altrimenti potenza(b,n)=b*potenza(b,n-1) Caso semplice: potenza(b, 0) = 1 Parte ricorsiva: ridefinire il problema mediante una definizione ricorsiva di più sottoproblemi: potenza(b,n)=b*potenza(b,n-1) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
La funzione ricorsiva potenza(b, n) long int potenza(int base, int esp) { long int pot; /*printf("dati di input: base=%d, esp=%d\n",base,esp);*/ if(esp==0) pot=1; else pot=base*potenza(base,esp-1); /*printf("potenza(%d, %d) = %d\n",base,esp,pot);*/ return pot; } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Permutazioni, disposizioni, combinazioni Permutazioni semplici di n oggetti distinti P(n) = n! Disposizioni semplici di n oggetti distinti presi k a k Dn,k = n (n 1) (n 2) ... (n k + 2) (n k + 1)= n!/(n-k)! Combinazioni semplici di n oggetti distinti presi k a k Cn,k = Dn,k/k!=n!/(k!(n-k)!) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Disposizioni Disposizioni semplici di n oggetti distinti presi k a k 2. D(n, k) = n!/(n-k)! = n*(n-1)!/[(n-1)-(k-1)]=n*D(n-1, k-1) 1. D(n,1) = n int dispo(int n, int k) { if(k==1) return(n); else return(n*dispo(n-1, k-1)); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Combinazioni Combinazioni semplici di n oggetti distinti presi k a k: C(n,k)= D(n,k)/k! int comb(int n, int k) { return(disp(n, k)/fat(k)); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Combinazioni Combinazioni semplici di n oggetti distinti presi k a k 2. C(n,k)= n!/(k!(n-k)!)=[n*(n-1)!]/[k*(k-1)!(n-1-(k-1))]= = n/k * C(n-1,k-1) = = n*C(n-1,k-1)/k 1. C(n,1) = n Un esercizio per voi! LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
La successione di Fibonacci F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n 2) Note storiche: Leonardo Fibonacci, 1170-1250, noto come Leonardo da Pisa, introdusse il sistema numerico arabo posizionale in Europa (Libro dell’abaco) Per esempio F(2) = 1 + 0 = 1 F(3) = 1 + 1 = 2 F(4) = 2 + 1 = 3 F(5) = 3 + 2 = 5 F(6) = 5 + 3 = 8 F(7) = 8 + 5 = 13 LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
#include <stdio.h>long int fibo(int);main(){int n; long int f;printf("\nInserire n: \t");scanf("%d", &n);f=fibo(n);printf(“Termine di posto %d = %ld\n", n, f);} La successione di Fibonacci /1 LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
long int fibo(int n) {if(n==0) return(0);else if(n==1) return(1); else return(fibo(n-1)+fibo(n-2));} La successione di Fibonacci /2 F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n -2) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
long int fibo(int n) {switch(n){ case 0: return(0);break; case 1: return(1);break; default: return(fibo(n-1)+fibo(n-2)); break;} La successione di Fibonacci /3 F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n -2) LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Altri problemi risolti ricorsivamente: Contare le occorrenze di un carattere in una stringa Ricerca lineare ricorsiva Ordinamento per inserimento ricorsivo LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Contare le occorrenze di un carattere in una stringa O la stringa è vuota oppure essa contiene caratteri. In tal caso le occorrenze del carattere che interessa sono la somma delle occorrenze nella coda della stringa +1, se il primo elemento della stringa è proprio il carattere sotto osservazione. int conta(char ch, char *str) { int ris; If(str[0]==‘\0’) ris=0; else if(ch==str[0]) ris=1+conta(ch,&str[1]); else ris=conta(ch,&str[1]); return (ris); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Contare le occorrenze di un carattere in una stringa include <stdio.h> #include <stdlib.h> int conta(char, char *); int main() { int y=0; y = conta('c',"stcrincgca"); printf(" d = %d\n", y); system("PAUSE"); return 0; } int conta(char ch, char *stri) { int ris; if(stri[0]=='\0') ris=0; else if(ch==stri[0]) ris=1+conta(ch,&stri[1]); else ris=conta(ch,&stri[1]); return (ris); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
int appartiene(int a[], int dim, int elem){ if(a[dim-1]==elem) return TROVATO; else { dim=dim-1; if(dim>=1) appartiene(a,dim,elem); else return NON_TROVATO; } } Ricerca lineare ricorsiva LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Ordinamento per inserimento ricorsivo/1 Se l’array ha un solo elemento allora non fare nulla, perché l’array è ordinato altrimenti ordina i primi n-1 elementi dell’array e quindi inserisci l’elemento di posto n, salvaguardando l’ordinamento LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
void ord(int a[], int dim){ int el; if (dim==1) return; else { el=a[dim-1]; dim=dim-1; ord(a,dim); inserisci(el,a,dim+1); }} Ordinamento per inserimento ricorsivo/2 LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Complementi LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Disposizioni int dispo2(int k, int n) { return(fat(n)/fat(n-k)); } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Moltiplicazione, potenza, somma, somma di quadrati /1 #include <stdlib.h> #include <stdio.h> #include <string.h> #define DIM 5 int molt(int, int); long int potenza(int, int); long int somma(int [], int); long int sommaq(int [], int); LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Moltiplicazione, potenza, somma, somma di quadrati /2 int main() { /* valido solo per m, n>0 */ int base, m=2, esp, n=3,p; long int pot; int a[DIM]={1,2,3,4,5}; p=molt(m,n); printf("%d x %d = %d\n",m,n,p); printf("\n\n"); base=m; esp=n; pot=potenza(base,esp); printf("%d ELEVATO A %d = %d\n\n\n",m,n,pot); printf("somma = %ld\n\n",somma(a,DIM)); printf("somma dei quadrati= %ld\n\n",sommaq(a,DIM)); system("PAUSE"); return 0;} LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Moltiplicazione, potenza, somma, somma di quadrati /3 int molt(int m, int n) { int prodotto; printf("dati di input: m=%d, n=%d\n",m,n); if(n==1) prodotto=m; else prodotto=m+molt(m,n-1); printf("molt(%d, %d) = %d\n",m,n,prodotto); return prodotto; } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Moltiplicazione, potenza, somma, somma di quadrati /4 long int potenza(int base, int esp) { int pot; printf("dati di input: base=%d, esp=%d\n",base,esp); if(esp==0) pot=1; else pot=base*potenza(base,esp-1); printf("potenza(%d, %d) = %d\n",base,esp,pot); return pot; } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Moltiplicazione, potenza, somma, somma di quadrati /5 long int sommaq(int a[], int dim) { if(dim==1) return a[dim-1]*a[dim-1]; else { return (sommaq(a,dim-1)+a[dim-1]*a[dim-1]); } } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Ricerca ricorsiva con indicazione della posizione /* al momento della chiamata trovato=0 */ void appartiene(int a[], int dim, int elem, int *posiz, int *trovato) { if(a[dim-1]==elem) {*trovato=1; *posiz=dim-1;} else { dim=dim-1; if(dim>=1)appartiene(a,dim,elem,posiz,trovato); } } LdL - LP1 - ver. 6 - lez. 10 - aa 05-06
Proposte di lavoro • Invertire un array di dati di tipo int • Invertire una parola • Ricercare un carattere in una stringa e riportare la posizione • Ricerca una parola in un array di parole • Calcolare l’intersezione tra due insiemi • Calcolare l’unione tra due insiemi • Calcolare il complemento di A in B LdL - LP1 - ver. 6 - lez. 10 - aa 05-06