LdL - LP1 - ver. 6 - lez aa Linguaggi di programmazione I La ricorsione Prof. Luigi Di Lascio Lezione 10
LdL - LP1 - ver. 6 - lez aa Funzioni Ricorsive In particolare: La definizione ricorsiva di una funzione utilizza la funzione stessa e una versione pi ù semplice di questa a.1 è un numero naturale b.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
LdL - LP1 - ver. 6 - lez aa Esempio: la definizione ricorsiva del fattoriale di n Se n=0 allora fat(n)=1 altrimenti fat(n)=n*fat(n-1) 1.0!=1 2. n!=n*(n-1)!
LdL - LP1 - ver. 6 - lez aa long int fat(int n) { long int fattoriale; if(n==0) fattoriale=1; else fattoriale=n*fat(n-1); return fattoriale; } Esempio: la definizione ricorsiva del fattoriale di n, limplementazione Se n=0 allora fat(n)=1 altrimenti fat(n)=n*fat(n-1)
LdL - LP1 - ver. 6 - lez aa Il proccesso ricorsivo
LdL - LP1 - ver. 6 - lez aa 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 aa Definizioni ricorsive/1 Vita quotidiana (anzi serale e mangereccia) Lordine di una o più pizze può essere cosi formulata: ordine := pietanza := margherita bruschetta vino conto := somma da pagare
LdL - LP1 - ver. 6 - lez aa Definizioni ricorsive/2 Definizioni ricorsive di libro libro := := qui definizione
LdL - LP1 - ver. 6 - lez aa Definizioni ricorsive/3 Definizioni ricorsive di libro, capitolo e paragrafo libro := capitolo := paragrafo : = testo := parola:= una stringa presente sul vocabolario di italiano
LdL - LP1 - ver. 6 - lez aa 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 Parte ricorsiva: somma(n) = a[n-1]+somma(n-1) Caso più semplice: la sequenza è costituita da un solo numero a[0]. In tal caso: somma = a[0]
LdL - LP1 - ver. 6 - lez aa 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 aa 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) Parte ricorsiva: ridefinire il problema mediante una definizione ricorsiva di più sottoproblemi: potenza(b,n)=b*potenza(b,n-1) Se n=0 allora potenza(b, 0) = 1, altrimenti potenza(b,n)=b*potenza(b,n-1) Caso semplice: potenza(b, 0) = 1
LdL - LP1 - ver. 6 - lez aa 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 aa Permutazioni, disposizioni, combinazioni Disposizioni semplici di n oggetti distinti presi k a k D n,k = n (n 1) (n 2)... (n k + 2) (n k + 1)= n!/(n-k)! Permutazioni semplici di n oggetti distinti P(n) = n! Combinazioni semplici di n oggetti distinti presi k a k C n,k = Dn,k/k!=n!/(k!(n-k)!)
LdL - LP1 - ver. 6 - lez aa 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 aa 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 aa 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 aa La successione di Fibonacci F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n 2) Per esempio F(2) = = 1 F(3) = = 2 F(4) = = 3 F(5) = = 5 F(6) = = 8 F(7) = = 13 Note storiche: Leonardo Fibonacci, , noto come Leonardo da Pisa, introdusse il sistema numerico arabo posizionale in Europa (Libro dellabaco)
LdL - LP1 - ver. 6 - lez aa #include 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 aa long int fibo(int n) { if(n==0) return(0); else if(n==1) return(1); else return(fibo(n-1)+fibo(n-2)); } F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n -2) La successione di Fibonacci /2
LdL - LP1 - ver. 6 - lez aa 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; } F(0) = 0 F(1) = 1 F(n) = F(n 1) + F(n -2) La successione di Fibonacci /3
LdL - LP1 - ver. 6 - lez aa 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 aa Contare le occorrenze di un carattere in una stringa 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); } 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.
LdL - LP1 - ver. 6 - lez aa Contare le occorrenze di un carattere in una stringa include #include 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 aa 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 aa Ordinamento per inserimento ricorsivo/1 Se larray ha un solo elemento allora non fare nulla, perché larray è ordinato altrimenti ordina i primi n-1 elementi dellarray e quindi inserisci lelemento di posto n, salvaguardando lordinamento
LdL - LP1 - ver. 6 - lez aa 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 aa Complementi
LdL - LP1 - ver. 6 - lez aa Disposizioni int dispo2(int k, int n) { return(fat(n)/fat(n-k)); }
LdL - LP1 - ver. 6 - lez aa Moltiplicazione, potenza, somma, somma di quadrati /1 #include #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 aa 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 aa 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 aa 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 aa 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 aa 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,trov ato); }
LdL - LP1 - ver. 6 - lez aa Proposte di lavoro 1.Invertire un array di dati di tipo int 2.Invertire una parola 3.Ricercare un carattere in una stringa e riportare la posizione 4.Ricerca una parola in un array di parole 5.Calcolare lintersezione tra due insiemi 6.Calcolare lunione tra due insiemi 7.Calcolare il complemento di A in B