API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della...

64
API 2013/4 Ricorsione Dipartimento di Elettronica, Informazione e Bioingegneria @ G. Gini 2013

Transcript of API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della...

Page 1: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

API 2013/4Ricorsione

Dipartimento di Elettronica, Informazione e Bioingegneria

@ G. Gini 2013

Page 2: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

costruttori, istruzioni, tipi dati

costruttore istruzione tipo dato___________________________________________________atomo assegnamento variabileenumerazione istruzione composta structripetizione nota for arrayscelta if structripetizione ignota while filericorsione funzione dati ricorsivigrafo go to puntatori

Page 3: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

ricorsione

Page 4: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Ricorsione: definizione

• Ricorsione significa richiamare il concetto che si definisce all'interno della definizione stessa.

Ad esempio la definizione dell'acronimo GNU (l'organizzazione che produce gran parte del software "libero") è ricorsiva dato che l'acronimo sta per:

"GNU's Not Unix" (GNU non e' Unix), ovvero GNU è una parte della definizione di GNU

Page 5: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

DATI RICORSIVI

Es: una espressione aritmetica(x+y) * (z + (3 - t))

• <exp> ::= <term><operatore><term>• <term> ::= <variabile>|<costante>(<exp>)• <variabile> ::= t | x | y | z | w• <operatore> ::= +|-|*|:• <costante> ::= 0|1|2|3Sono regole espresse in Backus-Naur formEs: La sommatoria di una sequenza di numeri

I dati ricorsivi non esistono in C ma esistono in altri linguaggi come LISP, Prolog

00

1=∑

=iia ∑∑

=+

+

=

+=n

iin

n

ii aaa

11

1

1

Page 6: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Algoritmo ricorsivo

Per entrare nella mia casa mi serve la chiaveLa chiave si trova in una casa più piccola- devo avere la chiave di una casa più piccola

Page 7: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Algoritmo ricorsivo:•Hai un algoritmo che funziona.•usalo.

La casa più piccolaè aperta (facilmente)

Page 8: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Chiamate ricorsive

• durante l’esecuzione di una funzione P avviene una nuova chiamata alla stessa P

ricorsione diretta: • P chiama se stessa durante la propria esecuzione

ricorsione indiretta: • P chiama durante la sua esecuzione la funzione Q• Q a sua volta chiama R, …• R chiama nuovamente P

Page 9: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

induzione matematica

• Se U è un sottoinsieme dell'insieme dei numeri naturali che verifica le seguenti due proprietà:

U contiene lo 0, ogni volta che U contiene un numero n contiene anche il numero successivo n + 1,

• allora U coincide con tutto l'insieme dei numeri naturali

Page 10: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

A che cosa serve?

• Per dimostrare che un certo asserto P(n) in cui compare un numero naturale n vale per qualunque n∈N :

1. si dimostra che vale P(0), cioè che 0 è nell'insieme U per cui vale P(n);

2. si assume come ipotesi che l'asserto P(n) valga per un generico n e da tale assunzione si dimostra che vale anche P(n + 1)

• Quindi si conclude che l'insieme U dei numeri per cui vale P(n) coincide con tutto l'insieme dei numeri naturali. Il punto 1 ègeneralmente chiamato base dell'induzione, il punto 2 passo induttivo

Page 11: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

induzione

S

i S S S S i S i

nS n

( )

,[ ( ), ( ), ( ),..., ( ) ( )]

( )

0

0 1 2 1∀ − ⇒

⎬⎪⎪

⎭⎪⎪

⇒ ∀

S

iS i S i

nS n

( )

( ) ( )

( )

0

1∀ ⇒ +

⎬⎪⎪

⎭⎪⎪

⇒ ∀

induzione forte (e ricorsione)

Page 12: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Induzione e ricorsione

⇒ ∀ − ⇒

⎬⎪⎪

⎭⎪⎪

⇒ ∀ ⇒

S

i S S S S i S i

nS n

( )

,[ ( ), ( ), ( ),..., ( ) ( )]

( )

0

0 1 2 1

S n( ) =

•Ipotesi induttiva:

``l’algoritmo ricorsivo funziona per ognipossibile n.''

Caso base

i

Page 13: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Terminazione

• evitare catene infinite di chiamateOccorre che le chiamate siano soggette a una condizione che prima o poi assicura che la catena terminiOccorre anche che l'argomento sia "progressivamente ridotto" dal passo induttivo, in modo da tendere prima o poi al caso base

Page 14: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Algoritmo ricorsivo

• Occupati di un passo allavolta.

• Astrazione utile per la correttezza

• Ogni istanza deve essere un casosemplificato dello stesso problema

• Conosci solo la tua istanza in ognimomento.

Pros: Cons:

Page 15: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4 15

• In un certo istante possono essere in corso diverseattivazioni della stessa funzione ricorsiva

Ovviamente sono tutte sospese tranne una, l'ultima invocata, all'interno della quale si sta svolgendo il flusso di esecuzione

• Ogni attivazione esegue lo stesso codice ma opera su copie distinte dei parametri e delle variabili locali

Esecuzione di funzioni ricorsive

Page 16: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

la gestione a pila della memoria

Variabili globali

main

record diattivazionedel main

P1

record diattivazionedi P1

P2’

record diattivazionedi P2’

P3

record diattivazionedi P3

P2” record diattivazionedi P2"

Page 17: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

gestione a pila della memoria

P1 P2’ P3 P2”main

Variabili globali

record diattivazionedel main

record diattivazionedi P1

record diattivazionedi P2’

record diattivazionedi P3

record diattivazionedi P2"

P3P2’

Page 18: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

la gestione a pila della memoria

Variabili globali

record diattivazionedel main

record diattivazionedi P1

record diattivazionedi P2’

P3P2’

main P1 P2’ P3 P2”

P4

record diattivazionedi P4

P2’P1main

Page 19: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

fattoriale iterativo (in C)

Consideriamo la funzione fattorialen! = n.(n - 1).(n - 2)...2.1.

Soluzione iterativa:Costruiamo il risultato partendo dal numero più

piccolo

long int fatt (int n){ int ris, i;ris = 1;for (i=1; i<=n; i++)

ris = ris*i;return ris;}

Page 20: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

fattoriale ricorsivo

Possiamo computare il fattoriale osservando che • n! = n.(n - 1)!• 0! = 1

long int fact_r (int n){ if (n==0)

return 1;else return n*fact_r(n-1);}

Page 21: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

L’esecuzione

record di attivazione

Seconda attivazione2

Terza attivazione1

Quarta attivazione0

1*1 = 1

2*1 = 2

Prima attivazione

n FattRic

3 3*2 = 6

1

Page 22: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Modello di sostituzione - fattoriale

a = fact_r (6);(* 6 (fact_r 5))(* 6 (* 5 (fact_r 4)))(* 6 (* 5 (* 4 (fact_r 3))))(* 6 (* 5 (* 4 (* 3 (fact_r 2)))))(* 6 (* 5 (* 4 (* 3 (* 2 (fact_r 1))))))(* 6 (* 5 (* 4 (* 3 (* 2 1)))))(* 6 (* 5 (* 4 (* 3 2))))(* 6 (* 5 (* 4 6)))(* 6 (* 5 24))(* 6 120)a = 720

Page 23: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4 23

MCD tra M e N (M, N naturali positivi)se M=N allora MCD è Nse M>N allora esso è il MCD(N, M-N)se N>M allora esso è il MCD(M, N-M)

MCD Euclide

30

12

12

18

6

18

6 6

1 caso base

2 passi induttivi

Page 24: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

MCD iterativo

int MCD (int m, n){while (m != n)

{if (m > n) m = m - n;else n = n - m; }

return m;}

Esempio di chiamata: a = MCD(30,18);

m =12 n= 18m=12 n= 6m=6 n= 6 a = 6

Page 25: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

MCD ricorsivo

int MCD (int m, n){ if (m == n)

return m;if (m > n)

return MCD (m - n, n);else

return MCD(m, n - m); }

Modello di sostituzione:A = MCD (30, 18);

Chiamate:MCD (30, 18)MCD (12, 18)MCD (12, 6)MCD (6, 6A = 6

Page 26: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

2n iterativo• calcolo il prodotto di 2 per se stesso n volte -

accumulo i valori di 2n

int power_2 (int n){int risultato = 1;while (n != 0)

{risultato = 2 * risultato;n = n-1;}

return risultato; }

risultato=1

risultato=2*risultaton=n-1

N=0 NO

risultato finale

Page 27: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

2n ricorsivo20 = 12n = 2 * 2 n-1

int power2 (int n){ if (n ==0)

return 1;else

return 2 * power2(n-1);}

Modello di sostituzione:A = power2(3);chiamate

2 * power2 (2)2 * 2 * power2 (1)2 * 2 * 2 * power2 (0)2 * 2 * 2 * 12 * 4A = 8

Page 28: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Il processi ricorsivi

• Il processo di MCD è lineare con le grandezze in gioco e non tiene computazioni in sospeso

MCD è un esempio di ricorsione efficace, tailrecursion.

• Il processo di fact_r è lineare con le grandezze in gioco e tiene una lista di computazioni in sospeso

Fact_r è un esempio di processo lineare ricorsivo

Page 29: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Sintassi ricorsiva e ciclo a contatore

Per calcolare il fattoriale in modo iterativo: moltiplichiamo 1 per 2, il risultato per 3, e così via fino a n.

Questo si ottiene mantenendo un contatore che va da 1 a n, mediante le due istruzioni:

• prodotto = contatore * prodotto• contatore = contatore + 1e fermandosi non appena il contatore supera n.

factorial (n) = fact-iter (1 1 n)-----------------------------------------------fact-iter (int prodotto, counter, max) -----------------------------------------------if counter > max then return prodotto

else return fact-iter ((counter*prodotto) (counter + 1) max)

fact_iter funziona come il ciclo for ma ha sintassi ricorsiva

Page 30: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Modello di sostituzione

Il processo di computazione di 6! evolve così:

A =factorial (6);

(fact-iter 1 1 6)(fact-iter 1 2 6)(fact-iter 2 3 6)(fact-iter 6 4 6)(fact-iter 24 5 6) (fact-iter 120 6 6)(fact-iter 720 7 6)A = 720

Page 31: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

es: Stringhe palindrome

• Palindrome = uguale se letta dall’inizio o dalla fine

palindroma (s) = if s=reverse(s) then return TRUE else return FALSE

• Esempi: 1991, 2002, aba, a, AI*IA, anilina, …

• Regole base per algoritmo ricorsivo: se lunghezza=1 è palindromase lunghezza=2 devono essere due caratteri ugualialtrimenti confronta primo e ultimo carattere

Page 32: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

codice palindromeint pal( char a[], int lun) {

if(lun == 1) return 1;if(lun == 2) {

if (a[0]==a[1]) return 1;else return 0;

} else {if(a[0]==a[lun-1]) return pal(a+1,lun-2);else return 0;

}}confronta i caratteri agli estremi: se uguali, richiama la funzione

sulla stringa che inizia dal secondo carattere ed è lunga due caratteri in meno della stringa precedente.

Se la stringa è palindroma ritorna 1, altrimenti 0

-L’algoritmo termina perché si giunge sicuramente a lunghezza 1 o 2

-Il numero delle chiamate è uguale alla metà della lunghezza dellastringa.

Page 33: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

RICORSIONE LINEARE E ITERAZIONE

Entrambi i processi richiedono un numero di passi proporzionale a n

• - Per MCD per ogni passo dobbiamo solo mantenere i valori di m e n. Questo processo è iterativo. Il tempo per computare MCD cresce linearmente con n. Per questo il processo è chiamato processo lineare iterativo. Le variabili di programma danno una descrizione completa del processo in ogni stato.

• Per fattoriale il processo si espande e poi si contrae: l'espansione è dovuta alle moltiplicazioni differite, la contrazione avviene quando gli argomenti della moltiplicazione sono valutati e la moltiplicazione eseguita. La lunghezza della catena di operazioni differite cresce linearmente con n. Perciò questo processo è chiamato lineare ricorsivo.

Page 34: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

la serie di Fibonacci

• Fibonacci (1202) partì dallo studio sullo sviluppo di una colonia di conigli in circostanze ideali

• Partiamo da una coppia di conigli• I conigli possono riprodursi all'età di un mese• Supponiamo che dal secondo mese di vita in poi,

ogni femmina produca una nuova coppia• e inoltre che i conigli non muoiano mai…

Quante coppie ci sono dopo n mesi?

Page 35: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

FibonacciSerie di Fibonacci: ogni numero è la somma dei due

precedenti: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...

Definizione ricorsiva:Fib(n) = se n=0 allora 0

se n=1 allora 1altrimenti Fib(n - 1)+Fib(n - 2)

long int fibonacci(int n ){if (n == 0 || n == 1)

return n;else

return fibonacci( n - 1) +fibonacci( n – 2 );

}

Page 36: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Computazione di fibonacci

f( 3 )

f( 1 )f( 2 )

f( 1 ) f( 0 ) return 1

return 1 return 0

return +

+return

Page 37: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

#include <stdio.h>

long int fibonacci( int );

main(){

long int result; int number;

printf( ”inserisci un intero: " );scanf( "%d", &number );result = fibonacci( number );printf( "Fibonacci( %d ) = %ld\n", number, result );

}

long int fibonacci( int n ){

if ( n == 0 || n == 1 )return n;

elsereturn fibonacci( n - 1 ) + fibonacci( n - 2 );

}

inserisci un intero: 10Fibonacci(10) = 55

inserisci un intero: 20Fibonacci(20) = 6765

Page 38: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

N=7

N=2

N=1N=1

N=2

N=1N=1

N=2

N=1N=1

N=1N=4N=3

b4b3

b7 = b3 × b4

int power (int b, int n)/* funzione che scompone l’esponente */{ if (n == 0) return 1;

if (n%2)return power(b, n/2) * power (b, n/2+1);

else return power(b, n/2) * power (b, n/2)}

Calcolare bn

Page 39: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

PROCESSI RICORSIVI AD ALBERO

il processo Fibonacci si biforca ad ogni livello, infatti fib èchiamata ricorsivamente due volte.

(fa molte computazioni ridondanti, perchè ripete circa metà del lavoro).

Questo processo richiede un tempo che cresce esponenzialmente con l'input.

Lo spazio cresce linearmente con l'input.

Page 40: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

ELIMINARE RICORSIONE ALBERO

Per calcolare il numero di Fibonacci e' opportuno cercare un processo iterativo.

Usiamo allora a e b, inizializzati ad 1 e a 0, e li trasformiamo mediante:• a <- a + b• b <- adopo n di queste trasformazioni, a = Fib(n), b = Fib (n-1)

fib (n) = fib-iter (1 0 n)

int fib-iter (int a, b , count) if count = 0 then return b

else return fib-iter( (a + b) a (count - 1))

Page 41: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Efficienza della ricorsione

• Una funzione scritta come MCD prende il nome di “tail recursive”: ha la stessa efficienza di una funzione iterativa

• Tradurre la ricorsione in tail recursion è un procedimento di ottimizzazione

Page 42: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Es: radice quadrata

Metodo iterativo di Newton • si parte da stima 1 • Si continua calcolando la nuova stima:

radice(numero) = media (stima, numero/stima)

radice-quadrata(int numero) = Newton (numero, 1)la radice temporanea viene inizializzata a 1

------------------------------------------------------------------------------------------------------------

float Newton (int numero, float rad_temp) if preciso (rad_temp, numero) then return rad_temp

else return Newton (numero, stima (rad_temp, numero))----------------------------------------------------------------------------------------------------------

boolean preciso (float prova, int numero)if | prova2 - numero | < 0.001 then return true else return false-------------------------------------------------------------------------------------------

float stima (float prova, int numero)return (prova+ numero/prova)/2

Page 43: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

es: radici di una equazioneTrovare radici di f(x)=0, f continua, dato f(a)<0<f(b), provando a

dimezzare l’intervallo

float search(function f, float neg, float pos) med <= (neg+pos)/2;

if vicino(med,pos) then return medif f(med)>0 then return search (f, neg, med))

else return search (f, med ,pos)

boolean vicino(float x,float y)-if abs(x-y)<0.001 then return true

else return false

neg pos

Page 44: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Aritmetica: prodotto sapendo fare l’addizione

• Il prodotto di due interi a e bc = a * b è dato da a+a+… +a

b volte

int prodotto(int a, int b)if a=0 or b=0 then return 0if b=1 then return a

else return a +prodotto (a, b-1)

Page 45: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Algoritmo egiziano per prodottoint prodotto (int a, int b)

int p = 0while a diverso da 0 do

if a dispari then p = b+pa = parte intera di a/2b = b*2

return p

in forma ricorsiva, Prodotto-ric (a, b, p) = prodotto (a, b, 0)int prodotto (int a, int b, int p)if a=0 then return pif (dispari a) then return prodotto(a/2, b*2, b+p)

else return prodotto (a/2, b*2, p)

Page 46: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Esempio: TORRE DI HANOI

• Ci sono 3 pioli e n dischi di grandezze diverse, che possono essere spostati uno alla volta e posti solo su pioli vuoti o sopra un disco piùgrande.

• Si parte con una torre su un piolo, due pioli vuoti, e si vuolericostruirla su un altro piolo.

A B C

Page 47: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Torre di Hanoi

da dove iniziare?

.

Page 48: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Torre di Hanoi

Ad un certopunto il disco più

grande va a posto. Lo farò io.

Page 49: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Torre di Hanoi

Per farlo, gli altridischi devono

essere nel mezzo a torre.

Page 50: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Torre di Hanoi

Come fanno a muoversi?Chiamo un

amico per farlo.Ed un altro per muoverli poi.

Io muovo solo ildisco grande.

Page 51: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

A B C

Soluzione ricorsiva

• Il caso banale e’ lo spostamento di un disco; • la soluzione ricorsiva: un passo intermedio della soluzione per n dischi è

quello in cui il disco maggiore è al posto finale e gli altri (n-1) dischi sono sul piolo di servizio.

siamo più vicini alla soluzione se la torre di n-1 è sul piolo di servizio il disco piu' grande é sul piolo finale;

basta costruirgli sopra la torre di n-1 dischi!

Page 52: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

La soluzione ricorsiva

void hanoi (int n, int a, int b, int c)if n = 1 then sposta-disco(a, c)

else [hanoi(n-1, a, c, b), sposta-disco(a, c), hanoi(n-1, b, a, c)]

Il gioco prevede 64 dischi. Quante mosse saranno da fare?

f(n) spostamenti per spostare una torre di n dischif(n) = f(n-1) + 1 + f(n-1) = 2 f(n-1)+1=2n -1f(64) = 264 -1 = circa 0.2 1020

Page 53: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

programma hanoi in C#include <stdio.h>#define DISCHI 3int mossa; /* variabile globale*/void hanoi (int, char, char, char);void muovi (int, char, char);

main (){mossa = 0;printf(“\nMosse da dare per spostare %d dischi”, DISCHI);hanoi (DISCHI, ‘A’, ‘B’, ‘C’); }/* Implementazione delle procedure*/void hanoi (int n, char iniz, char fin, char inter){if (n ==1) muovi (1, iniz, fin);

else {hanoi(n-1, iniz, inter, fin); muovi (n, iniz, fin);hanoi(n-1, inter, fin, iniz); } }

void muovi(int ndischi, char da, char fino){char invio;mossa = mossa+1;printf(“\n%3d”, mossa);printf(“:muovi disco %d da %c a %c”, ndischi, da, fino);scanf (“%c”, &invio);}

Page 54: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Es: funzione di Ackerman

• La funzione di Ackermann e` una funzione totale (sui Naturali) calcolabile ma non primitiva ricorsiva.

• Cresce MOLTO rapidamente.• Definisce una famiglia di funzioni al variare di un parametro

individuato dalla prima variabile. Per ogni valore del parametro si ha una funzione che èottenuta iterando la funzione precedente per un numero di volte individuato dalla seconda variabile.

Page 55: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

/* Funzione ricorsiva che calcola la funzione di Ackermann di due naturali >=0 . Gia' calcolando ack(4,1) si puo' avere stack overflow! */

#include <stdio.h> long int ackermann (int m, int n) { if (m < 0 || n < 0) return -1; /* ack non e'

definita per interi negativi! */ if (m == 0) return n+1;

else if (n == 0) return ackermann(m-1,1); else return ackermann(m-1,ackermann(m,n-1)); }

main ();{ int m, n;

printf("Inserire un intero m >= 0 : "); scanf("%d", &m); printf("Inserire un intero n >= 0 : "); scanf("%d", &n); printf("Ackermann(%d,%d) = %d!\n", m, n, ackermann(m,n));

}

Page 56: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Modello di sostituzione

Page 57: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Immagini ricorsive

if n=0, disegna

else disegna

… e ricorsivamente con n-1

if n=1

n=0

Page 58: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

if n=0, disegna

else disegna

… e ricorsivamente con n-1

if n=2

n=1

Page 59: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

if n=0, disegna

else disegna

… e ricorsivamente con n-1

if n=30

Page 60: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Immagini ricorsive

if n=1if n=2if n=3if n=4if n=5

if n=0

Page 61: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Immagini ricorsive

if n=1

if n=0

if n=2if n=3if n=4if n=5

Page 62: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Fiocco di neve di Koch

Ricorsione da 1 a 6

Page 63: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

Curva di Hilbert• È una curva che riempie lo spazio visitando ogni punto in una griglia.

• Gli elementi sono "cups" (un quadrato con un lato aperto) ) e "joins" (un vettore che unisce 2 cups).

Ogni cup ha 2 terminazioni, ed ognuna può essere inizio o fine. Quindi ci sono 8 varietà di cup.join ha una direzione secondo uno dei 4 punti cardinali.

• Una curva di Hilbert del primo ordine è una cup singola, nello spazio 2x2.

• La curva del secondo ordine rimpiazza la cup con 4 cup legate fra loro da 3 join.

• Nel terzo ordine ogni cup è rimpiazzata da 4, e così via.

Primo e secondo ordine

Page 64: API 2013/4 - Intranet DEIBhome.deib.polimi.it/gini/API/docs/01-ricorsione.pdf · all'interno della quale si sta svolgendo il flusso di esecuzione ... tail recursion. ... ogni numero

G. Gini 2013/4

codice

enum { UP, LEFT, DOWN, RIGHT}; void hilber_level(int level,int

direction=UP) { if (level==1)

{ switch (direction) {/* move() traccia linea nella direzione */

case LEFT: move(RIGHT); move(DOWN); move(LEFT); break;

case RIGHT: move(LEFT); move(UP); move(RIGHT); break;

case UP: move(DOWN); move(RIGHT); move(UP);break;

case DOWN: move(UP); move(LEFT); move(DOWN);break; } /* fine switch */ }

else { switch (direction)

{ case LEFT:hilbert_level(level-1,UP); move(RIGHT); hilbert_level(level-1,LEFT); move(DOWN); hilbert_level(level-1,LEFT); move(LEFT); hilbert_level(level-1,DOWN); break;

case RIGHT: hilbert_level(level-1,DOWN); move(LEFT); hilbert_level(level-1,RIGHT); move(UP); hilbert_level(level-1,RIGHT); move(RIGHT); hilbert_level(level-1,UP); break;

case UP: hilbert_level(level-1,LEFT); move(DOWN); hilbert_level(level-1,UP); move(RIGHT); hilbert_level(level-1,UP); move(UP); hilbert_level(level-1,RIGHT); break;

case DOWN: hilbert_level(level-1,RIGHT); move(UP); hilbert_level(level-1,DOWN); move(LEFT); hilbert_level(level-1,DOWN); move(DOWN); hilbert_level(level-1,LEFT); break; } /* fine switch */ } /* fine if else*/ }