La ricorsione.

Slides:



Advertisements
Presentazioni simili
INFORMATICA Algoritmi fondamentali
Advertisements

Funzioni e procedure Ogni linguaggio di programmazione ad alto livello mette a disposizione del programmatore questi strumenti, ed il C non è da meno!
Sottoprogrammi: funzioni e procedure
Scomposizione funzionale
© 2007 SEI-Società Editrice Internazionale, Apogeo Unità E1 Dallanalisi del problema alla definizione dellalgoritmo.
Ricorsione Procedure e funzioni ricorsive. Definizioni Un oggetto si dice ricorsivo se è definito totalmente o parzialmente in termini di sé stesso La.
Analisi della complessità degli algoritmi
Procedure e funzioni A. Ferrari.
Procedure e funzioni ricorsive
Capitolo 8 Sistemi lineari.
MATLAB.
MATLAB. Scopo della lezione Programmare in Matlab Funzioni Cicli Operatori relazionali Esercizi vari.
Informatica Generale Marzia Buscemi
Fondamenti di Informatica CDL in Ingegneria Gestionale (B)- A.A CDL in Ingegneria Gestionale (B)- A.A Programmazione Ricorsiva.
Lez. 31 Universita' di Ferrara Facolta' di Scienze Matematiche, Fisiche e Naturali Laurea Specialistica in Informatica Algoritmi Avanzati Programmazione.
Lez. 41 Universita' di Ferrara Facolta' di Scienze Matematiche, Fisiche e Naturali Laurea Specialistica in Informatica Algoritmi Avanzati Programmazione.
1 Istruzioni, algoritmi, linguaggi. 2 Algoritmo per il calcolo delle radici reali di unequazione di 2 o grado Data lequazione ax 2 +bx+c=0, quali sono.
Introduzione agli algoritmi. Definizione Sistema di regole e procedure di calcolo ben definite che portano alla soluzione di un problema con un numero.
Iterazione enumerativa (for)
PROGRAMMI DI RICERCA E ORDINAMENTO
Informatica 2. Concetti fondamentali di programmazione Programmare vuol dire scrivere un algoritmo in un linguaggio che faccia funzionare un calcolatore.
CORSO DI PROGRAMMAZIONE II
CORSO DI PROGRAMMAZIONE II Introduzione alla ricorsione
G.M. - Informatica B-Automazione 2002/03 Funzione Indica una relazione o corrispondenza tra due o più insiemi che soddisfa ad alcune proprietà. Il dominio.
Introduzione alla Ricorsione
La Programmazione Ricorsiva
Fondamenti di Informatica1 Ripetizioni di segmenti di codice Spesso è necessario ripetere più volte uno stesso segmento dell'algoritmo (e.g. I/O, elaborazioni.
Algoritmi e diagrammi di flusso
Javascript 6 Funzioni. Una funzione sarà eseguita in risposta ad un evento o ad una chiamata diretta. Le funzioni possono essere inserite comodamente.
Biologia Computazionale - Algoritmi
1 Programmazione = decomposizione basata su astrazioni (con riferimento a Java)
Elementi di Informatica di base
INFORMATICA MATTEO CRISTANI.
Esercizio 10.* Un cassiere vuole dare un resto di n centesimi di euro usando il minimo numero di monete. a) Descrivere un algoritmo goloso per fare ciò.
Algoritmi e Strutture Dati
Lezione 6 Strutture di controllo Il condizionale
Il linguaggio C Le funzioni C Language Il passaggio dei parametri
Un esempio: Calcolo della potenza n-esima di un numero reale
ISTITUTO STATALE DI ISTRUZIONE SUPERIORE F. ENRIQUES CORSO JAVA – PROVA INTERMEDIA DEL 12 MARZO 2007 NOME: COGNOME: ________________________________________________________________________________.
Complessità di un algoritmo
1 Fabio Scotti ( ) Laboratorio di programmazione per la sicurezza Valentina Ciriani ( ) Laboratorio di programmazione Lezione 11 e 12 -
Sistemi e Tecnologie Informatiche Ricorsione Umberto Ferraro Petrillo.
Array (ordinamento) CORDA – Informatica A. Ferrari.
PROPAGAZIONE DEGLI ERRORI:
Introduzione a Javascript
R 255 G 211 B 8 R 255 G 175 B 0 R 127 G 16 B 162 R 163 G 166 B 173 R 104 G 113 B 122 R 234 G 234 B 234 R 175 G 0 B 51 R 0 G 0 B 0 R 255 G 255 B 255 Supporting.
GLI ALGORITMI VISIBILE SUL BLOG INFORMATICA ANNO SCOLASTICO 2013 / 2014 GABRIELE SCARICA 2°T.
Didattica e Fondamenti degli Algoritmi e della Calcolabilità Terza giornata: principali classi di complessità computazionale dei problemi Guido Proietti.
Allievi Elettrici - AA Le funzioni ricorsive in C
1 Fabio Scotti – Università degli Studi di Milano Fabio Scotti ( ) Laboratorio di programmazione per la sicurezza Valentina Ciriani ( )
Lo strano mondo degli algoritmi di ordinamento Algoritmi.
1 Informatica Generale Alessandra Di Pierro Ricevimento: Giovedì ore presso Dipartimento di Informatica, Via Buonarroti,
Algoritmi.
Linguaggio C: Le basi Stefano Cagnoni e Monica Mordonini
Linguaggio C: Le basi Stefano Cagnoni e Monica Mordonini
1 Informatica Generale Marzia Buscemi Ricevimento: Giovedì ore , Dipartimento di Informatica, stanza 306-PS o per posta.
Flusso di Costo Minimo Applicazione di algoritmi: Cammini Minimi Successivi (SSP) Esercizio 1 Sia data la seguente rete di flusso, in cui i valori riportati.
Informatica 4 La ricorsione. Definizione di ricorsione Ricorsione è la proprietà di quei programmi che, all’interno delle istruzioni che li compongono,
Complessità Computazionale
Problema dell’Ordinamento. Problema dell’ordinamento Formulazione del problema –Si vuole ordinare una lista di elementi secondo una data proprietà P Esempio:
GLI ALGORITMI DI ORDINAMENTO
Sistemi e Tecnologie Informatiche Complessità di calcolo.
Informatica 3 V anno.
“ Pseudocodice ” Un programma per computer lavorerà su in insieme di “ variabili ” contenenti i dati del problema, soluzioni intermedie, soluzioni finali.
Analisi matematica Introduzione ai limiti
Informatica Problemi e algoritmi. una situazione che pone delle domande cui si devono dare risposte. Col termine problema o situazione problematica s’indica.
Sistemi di equazioni lineari. Sistemi di primo grado di due equazioni a due incognite Risolvere un sistema significa trovare la coppia di valori x e y.
La scrittura decimale Quando un numero è scritto in forma decimale, vi è un numero finito di cifre dopo la virgola. Ma sappiamo che ci sono divisioni “che.
10. Programmazione Ricorsiva Ing. Simona Colucci Informatica - CDL in Ingegneria Industriale- A.A
Lezione n. Parole chiave: Corso di Laurea: Insegnamento: Docente: A.A Salvatore Cuomo La ricorsione 15 Approccio ricorsivo, esercizi sulla.
Transcript della presentazione:

La ricorsione

Introduzione Nel corpo di un sottoprogramma è possibile attivare sottoprogrammi dichiarati esternamente o localmente al sottoprogramma, ma è anche possibile riattivare il sottoprogramma stesso. In quest’ultimo caso si parla di sottoprogrammi ricorsivi, caratteristica prevista da alcuni linguaggi di programmazione. Parliamo, quindi, di ricorsività diretta quando cerchiamo di definire qualcosa riferendoci (ossia “ricorrendo”) alla sua stessa definizione. In generale un oggetto si può definire ricorsivo quando viene definito in termini di se stesso.

Un esempio Proviamo a calcolare la seguente potenza: 78. Dalla matematica sappiamo che la potenza an è così definita: an = 1 se n = 0 con a  0 an = a * a * ..... a se n > 0 dove a è un numero intero o reale diverso da zero e n è un numero intero non negativo. La potenza di numero può essere espressa anche dalla seguente definizione (matematica) ricorsiva: an = a * an-1 se n> 0 dove an-1 = a* an-2 an-2 = a * an-3 ecc. Ritornando al nostro esempio abbiamo che: 78 = 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 Dalla precedente definizione, quindi, è vero che 78 = 7 * 77 dove 77 = 7 * 76 e 76 = 7 * 75 e così via Pertanto, 78 richiama 77, 77 richiama 76 e così sino al termine del calcolo. Quindi, partendo dal valore 71, si può giungere alla determinazione di 78 attraverso il procedimento inverso.  

Gli elementi del procedimento ricorsivo Possiamo affermare che per attivare un procedimento ricorsivo: il problema può essere scomposto in sottoproblemi dello stesso tipo, ognuno dipendente dall’altro in base ad una scala gerarchica; è necessario conoscere la soluzione di un caso particolare del problema (nel nostro caso 70) indispensabile per terminare il problema (condizione di terminazione); si devono conoscere le relazioni funzionali che legano il problema ai sottoproblemi simili. Abbiamo pertanto tre elementi caratteristici: Una condizione che permette di verificare se si è di fronte ad un caso particolare risolvibile banalmente o se è necessario procedere per più passate. La soluzione del caso banale. La soluzione più generale che contiene una o più chiamate ricorsive nel quale una relazione funzionale lega il problema ai sottoproblemi simili.

Un altro esempio Proviamo a calcolare il fattoriale di un numero N. Sappiamo che il fattoriale di un numero naturale N maggiore di zero è uguale a: N! = N * (N - 1)! Più precisamente possiamo dare la seguente definizione (matematica) ricorsiva di fattoriale: Fatt(0) = 1 se N=0 Fatt(N) = Fatt(N-1)*N se N >0 Riferendoci a 7! avremo:. 7! = 7 * 6 * 5 * 4 * 3 * 2 * 1 = 5040 che è uguale a 7! = 7 * 6! = 7 * 6 * 5! = 7 * 6 * 5 * 4! = 7 * 6 * 5 * 4 * 3! = 7 * 6 * 5 * 4 * 3 * 2! = 7 * 6 * 5 * 4 * 3 * 2 * 1! = 7 * 6 * 5 * 4 * 3 * 2 * 1 * 0! = 7 * 6 * 5 * 4 * 3 * 2 * 1 * 1 = 5040 Questo problema è stato espresso in termini ricorsivi in quanto risponde esattamente ai tre requisiti enunciati pocanzi. Infatti: sappiamo che calcolare N! dipende esclusivamente dal calcolo di (N-1)! abbiamo il caso particolare che 0! = 1 abbiamo una relazione funzionale N! = N * (N-1)! che lega il problema principale al sottoproblema. 

La funzione Fattoriale( ) FUNZIONE Fattoriale(Num : INTERO) : INTERO INIZIO SE (Num = 0) ALLORA Fatt 1 ALTRIMENTI Fatt  Num * Fattoriale(Num -1) FINESE RITORNO (Fatt) FINE Eseguiamo passo dopo passo le funzioni in modo da apprendere completamente il meccanismo della ricorsione.

Il procedimento di calcolo per la funzione Fattoriale( ) Calcoliamo Fatt(5). Considerato che Num è diverso da zero, si inizia il processo con l’istruzione: Fatt  Num * Fattoriale(Num -1) che corrisponde a eseguire (a) Fatt  5 * 4! (cioè calcola 5!) Ma noi non conosciamo ancora il valore di 4! per cui la moltiplicazione non può ancora essere eseguita. Per questo motivo si esegue di nuovo l’algoritmo per calcolare 4!. Ora Num vale 4, la condizione Num = 0 è ancora falsa, così viene eseguita nuovamente l’istruzione contenuta nel ramo ALTRIMENTI che corrisponde a calcolare: (b) Fatt  4 * 3! (cioè calcola 4!) Il procedimento prosegue con le seguenti istruzioni (c) Fatt  3 * 2! (cioè calcola 3!) (d) Fatt  2 * 1! (cioè calcola 2!) (e) Fatt  1 * 0! (cioè calcola 1!) A questo punto Num = 0 per cui viene eseguita l’istruzione contenuta nel ramo ALLORA cioè Fatt  1 che non richiede ulteriori esecuzioni dell’algoritmo. Il valore 1 assegnato alla variabile Fatt ci permette di procedere in quanto non richiede ulteriori esecuzioni dell’algoritmo. Il proseguimento avviene a ritroso così da terminare l’esecuzione delle istruzioni (e) (d) (c) (b) (a) rimaste sospese; quindi: nell’istruzione (e) 0! viene sostituito con 1. Ciò permette il calcolo di 1! che è uguale a 1; nell’istruzione (d) 1! viene sostituito con 1. Ciò permette il calcolo di 2! che è uguale a 2; nell’istruzione (c) 2! viene sostituito con 2. Ciò permette il calcolo di 3! che è uguale a 6; nell’istruzione (b) 3! viene sostituito con 6. Ciò permette il calcolo di 4! che è uguale a 24; nell’istruzione (a) 4! viene sostituito con 24. Ciò permette il calcolo di 5! che è uguale a 120.

Le chiamate ricorsive Graficamente il procedimento è il seguente: 5! 1° proc. ricorsivo 5* 4! 5 * 24 = 120 5° calcolo 2° proc. ricorsivo 4 * 3! 4 * 6 = 24 4° calcolo 3° proc. ricorsivo 3 * 2! 3 * 2 = 6 3° calcolo 4° proc. ricorsivo 2 * 1! 2 * 1 = 2 2° calcolo 5° proc. ricorsivo 1* 0! 1 * 1 = 1 1° calcolo

Ricorsione indiretta Si parla di ricorsione indiretta quando nella definizione di una funzione compare la chiamata a un'altra funzione la quale direttamente o indirettamente chiama la funzione iniziale. FUNZIONE ping(N:INTERO) INIZIO         SE (n < 1)             RITORNO (1)         ALRIMENTI              RITORNO( pong(n - 1) )     FINE FUNZIONE pong(N:INTERO)         SE (n < 0)             RITORNO 0         ALTRIMENTI             RITORNO ( ping(n/2) )    In questo esempio i metodi sono cooperanti nel senso che si invocano ripetutamente a vicenda (indirettamente), dando luogo a un caso particolare di ricorsione indiretta chiamata ricorsione mutua.

Problemi con la ricorsione Quando si inizia a scrivere funzioni ricorsive si incorre in alcuni problemi dovuti alla mancanza di familiarità con questo tipo di meccanismo. Per analizzare questi problemi consideriamo la funzione somma(N) che restituisce la somma dei primi N numeri interi. Ad esempio, se N vale 4 deve restituire 1+2+3+4 = 10. 1 se N = 1 somma(N) = N + somma(N-1) se N > 1 Pseudocodice FUNZIONE somma (N:INTERO) INIZIO SE(N = 1) RITORNO (1) ALTRIMENTI RITORNO ( N + somma(N -1)) FINE

Ricorsione infinita (1) In una ricorsione infinita vengono attivate infinite chiamate della funzione senza che esse vengano mai chiuse. Ciò può verificarsi: quando i valori del parametro non si semplificano. Per esempio, vediamo che cosa succede nell'implementazione della funzione somma( ) quando il valore del parametro non si semplifica. FUNZIONE somma (N:INTERO) INIZIO SE(N = 1) RITORNO (1) ALTRIMENTI RITORNO ( N + somma(N) ) FINESE FINE Esempio di chiamate ricorsive somma(5)  ( 5 +somma(5))  ( 5 + ( 5 + somma(5)) ) ( 5 + ( 5 + ( 5 + somma(5))) ) …. ricorsione infinita non viene mai risolta somma(5) il valore di N non si semplifica

Ricorsione infinita (2) Ricorsione infinita quando manca la clausola di chiusura per terminare. Per esempio, vediamo che cosa succede nell'implementazione della funzione somma( ) quando omettiamo la gestione dei casi base: FUNZIONE somma (N:INTERO) INIZIO RITORNO ( N + somma(N -1) ) FINE Esempio di chiamate ricorsive somma(5)  ( 5 +somma(4))  ( 5 + ( 4 + somma(3)) ) ( 5 + ( 4 + ( 3 + somma(2))) )  ( 5 + ( 4 + ( 3 + ( 2 + somma(1)))) )  ( 5 + ( 4 + ( 3 + ( 2 + 1 + somma(-1)))) )  ( 5 + ( 4 + ( 3 + ( 2 + 1 + (-1 + somma(-2))))) )……. ricorsione infinita il parametro N viene decrementato all’infinito Manca la clausola di chiusura

Ricorsione infinita nella ricorsione indiretta (1) in una ricorsione indiretta (le due funzioni si chiamano continuamente a vicenda) può verificarsi uno dei problemi visti in precedenza (senza cioè che si semplifichi il parametro o senza che esista la clausola di terminazione). Consideriamo, per esempio, le due seguenti funzioni mutuamente ricorsive: FUNZIONE pong(N:INTERO) INIZIO         SE (n < 0)             RITORNO  (0)         ALTRIMENTI             RITORNO ( ping(n -1) )    FINE Esempio di chiamate ricorsive ping(2)  ( pong(1))  ( ping(0) ) (pong(-1) )  0 FUNZIONE ping(N:INTERO) INIZIO         SE (n < 0)             RITORNO (1)         ALRIMENTI              RITORNO( pong(n - 1) )     FINE

Ricorsione infinita nella ricorsione indiretta (2) Se per un errore scrivessimo: FUNZIONE pong(N:INTERO) INIZIO         SE (n < 0)             RITORNO  (0)         ALTRIMENTI             RITORNO ( ping(n) )    FINE FUNZIONE ping(N:INTERO) INIZIO         SE (n < 1)             RITORNO (1)         ALTRIMENTI              RITORNO( pong(n) )     FINE il valore di N non si semplifica Avremmo: ping(2)  ( pong(2))  ( ping(2) ) (pong(2 )  ricorsione infinita

Ricorsione alle olimpiadi di informatica Considera il seguente problema proposto alla selezione scolastica delle olimpiadi di informatica: (il testo è stato adattato allo pseudocodice). Considera la seguente funzione: FUNZIONE ES3( x: INTERO ) INIZIO SE ( x ≤ 1 ) ALLORA RITORNO ( 0 ) ALTRIMENTI RITORNO (1 + ES3( x DIV 2 ) ) FINESE FINE Dove X DIV 2 è la divisione intera di x per 2 quindi, ad esempio: 7 DIV 2 restituisce 3. Che cosa restituisce la chiamata ES3( 10 ) ?. a) 1 b) 2 c) 3 d) nessuna delle precedenti

Ricorsione nelle funzioni di ricerca (1) Algoritmo ricorsivo di ricerca di un elemento in un vettore ordinato Pseudocodice FUNZIONE RicercaBinariaRic (VAL Vet: Vettore,VAL x:INTERO, VAL Inizio: INTERO, VAL Fine: INTERO): BOOLEANO Mezzo: INTERO INIZIO SE(Inizio > Fine) ALLORA RITORNO (Falso) FINESE Mezzo  (Inizio + Fine) DIV 2 SE(Vet[Mezzo] = x) RITORNO (Vero) ALTRIMENTI SE(Vet[Mezzo] > x) RITORNO ( RicercaBinariaRic(Vet, x, Inizio, Mezzo -1) ) RITORNO (RicercaBinariaRic(Vet, x, Mezzo + 1, Fine)) FINE

Ricorsione nelle funzioni di ricerca (2) Analisi dell’algoritmo Si cerca l’elemento in mezzo al vettore ((Inizio + Fine) DIV 2 ). Se non lo si trova e l’elemento da cercare è minore dell’elemento presente in mezzo al vettore, si effettua la ricerca con una chiamata ricorsiva della funzione nella prima metà del vettore passando come parametri l’indice di inizio e quello di mezzo meno uno. Se, invece, l’elemento da cercare è maggiore dell’elemento presente in mezzo al vettore, si effettua la ricerca con una chiamata ricorsiva della funzione nella seconda metà del vettore passando come parametri l’indice di mezzo più uno e l’indice di fine del vettore. Continuando con le invocazioni ricorsive si può arrivare: a un vettore di tre elementi: se non è quello di mezzo, si continua la ricerca su due vettori di un elemento ciascuno a un vettore di due elementi Fine = Inizio+1: abbiamo i valori Mezzo=Inizio=Fine-1; si continua fra Inizio, Inizio-1 oppure fra Fine, fine a un vettore di un elemento: se non è quello da cercare, si continua fra Inizio, Inizio-1 oppure fra Fine+1, Fine Prima o poi si arriva al caso: Fine=Inizio -1 che corrisponde alla ricerca in un vettore di zero elementi. E’ questo il caso base in cui si deve ritornare Falso. Esempio di chiamata iniziale della funzione Per effettuare la ricerca dell’elemento 25 nel vettore V di 100 elementi, si invocherà la funzione nel seguente modo: RicercaBinariaRic(V , 25 , 1, 100)

Ricorsione nelle funzioni di ordinamento (1) Algoritmo BubbleSort ricorsivo per l’ordinamento degli elementi di un vettore Vediamo la versione ricorsiva dell’algoritmo BubbleSort per l’ordinamento degli elementi di un vettore. FUNZIONE BubbleSortRic(REF Vet: Vettore, Fine: INTERO) i, Comodo:INTERO INIZIO SE(Fine ≠ 0) ALLORA PER i = 0 A Fine-1 ESEGUI SE(Vet[i] > Vet[i+1]) Comodo Vet[i] Vet[i] Vet[i+1] Vet[i+1] Comodo FINESE FINEPER BubbleSortRic(Vet, Fine-1) FINE

Ricorsione nelle funzioni di ordinamento (2) Analisi dell’algoritmo Nell’ordinamento a bolle dobbiamo far risalire gli elementi più piccoli fino alla cima del vettore. Il ciclo for pone l’elemento maggiore alla fine del vettore. Dopo aver fatto questo, resta da ordinare il resto del vettore cioè tutti gli altri elementi tranne l'ultimo. Nella chiamata ricorsiva viene specificato dove il vettore termina. Dove, cioè, finisce la parte di vettore ancora da ordinare. Facciamo il ciclo di confronti per mettere l’elemento maggiore alla fine. Successivamente effettuiamo l’ invocazione ricorsiva su tutto il vettore tranne l’ultimo elemento. La parte di vettore da ordinare diventa così sempre più piccola a ogni invocazione ricorsiva. Alla prima invocazione la variabile Fine vale la lunghezza del vettore -1 poi diminuisce di uno, poi ancora di uno, e così via. Quando la variabile Fine vale 0, la parte di vettore da ordinare è il solo primo elemento (che è già ordinato!). E’ questo il caso base in cui la funzione termina. Esempio di chiamata iniziale della funzione Per effettuare l’ordinamento del vettore V di 100 elementi, si invocherà la funzione nel seguente modo: BubbleSortRic(V, 100)