Top STACK Top Le operazioni fondamentali che si fanno sugli stack sono: riempimento e svuotamento. Questo implica che durante lo svolgimento del programma.

Slides:



Advertisements
Presentazioni simili
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Advertisements

                      Insertion-Sort
Ricorsione Procedure e funzioni ricorsive. Definizioni Un oggetto si dice ricorsivo se è definito totalmente o parzialmente in termini di sé stesso La.
Procedure e funzioni ricorsive
PROGRAMMARE IN PASCAL (le basi)
MATLAB. Scopo della lezione Programmare in Matlab Funzioni Cicli Operatori relazionali Esercizi vari.
Algoritmi e Programmazione
Informatica Generale Marzia Buscemi
Lez. 41 Universita' di Ferrara Facolta' di Scienze Matematiche, Fisiche e Naturali Laurea Specialistica in Informatica Algoritmi Avanzati Programmazione.
Strutture dati elementari
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Ordinamenti ottimi.
Algoritmi e Strutture Dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Iterazione enumerativa (for)
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
Algoritmi e strutture Dati - Lezione 7
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
Il problema del dizionario
Algoritmi e Strutture Dati
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
CORSO DI PROGRAMMAZIONE II Introduzione alla ricorsione
CORSO DI PROGRAMMAZIONE II
Algoritmi e Strutture Dati (Mod. B)
Algoritmi e Strutture Dati (Mod. A)
Alberi di Ricorrenza Gli alberi di ricorrenza rappresentano un modo conveniente per visualizzare i passi di sostitu- zione necessari per risolvere una.
e array a più dimensioni
Introduzione alla programmazione lll
07/04/2003Algoritmi Ricerca in una sequenza di elementi Data una sequenza di elementi, occorre verificare se un elemento fa parte della sequenza oppure.
Studente Claudia Puzzo
Algoritmi su Tipi Semplici
Relatori: Emanuele e Denis Tornei Informatici. Introduzione In queste prime lezioni abbiamo affrontato linformatica procedendo a soluzioni di problemi,
Problema Ci sono 5 signore nel parco. Ognuna di loro ha 1 figlio. Ogni bambino ha 10 figurine di calciatori, per un totale quindi di 50 figurine. Questi.
OPERAZIONI CON STRINGHE Le operazioni più interessanti da fare, per ora, con le stringhe sono: determinare la lunghezza della stringa, cioè quanti caratteri.
CAPITOLO 7.
FILE TESTO OUTPUT INPUT + DATI PROGRAMMA OUTPUT INPUT PROGRAMMA CARICAMENTO DATI FILE DATI.
CAPITOLO 15.
CAPITOLO 6.
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ò.
Radix-Sort(A,d) // A[i] = cd...c2c1
La complessità media O(n log n) di Quick-Sort vale soltanto se tutte le permutazioni dell’array in ingresso sono ugualmente probabili. In molte applicazioni.
ALGORITMI a.
Algoritmi CHE COS’è UN ALGORITMO di ORDINAMENTO?
Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 1 Cicli ed asserzioni Corso di Informatica 2 a.a. 2003/04 Lezione 1.
Array (ordinamento) CORDA – Informatica A. Ferrari.
La ricorsione.
GLI ALGORITMI VISIBILE SUL BLOG INFORMATICA ANNO SCOLASTICO 2013 / 2014 GABRIELE SCARICA 2°T.
Esercitazione su Vector. Permette di definire collezioni di dati generiche, che sono in grado di memorizzare elementi di ogni sottotipo di Object Definito.
Allievi Elettrici - AA Le funzioni ricorsive in C
PROVA INTERCORSO MOD.B a.a RICORSIONE ESERCIZI A1.1-A1.6.
Algoritmi e Strutture Dati Strutture Dati Elementari.
Ordinamento in tempo lineare Il limite inferiore Ω(n log n) vale per tutti gli algoritmi di ordinamento generali, ossia per algoritmi che non fanno alcuna.
RossiUgo /8796 BianchiCarlo /8746 II I Sia dato un file di testo riguardante un insieme di studenti di cui è.
Algoritmi e Strutture Dati
Paola Disisto, Erika Griffini, Yris Noriega.  Insieme ordinato di operazioni non ambigue ed effettivamente computabili che, quando eseguito, produce.
CORSO DI PROGRAMMAZIONE II
1 Ordinamento (Sorting) INPUT: Sequenza di n numeri OUTPUT: Permutazione π = tale che a 1 ’  a 2 ’  … …  a n ’ Continuiamo a discutere il problema dell’ordinamento:
Algoritmi e strutture Dati - Lezione 7 1 Algoritmi di ordinamento ottimali L’algoritmo Merge-Sort ha complessità O(n log(n))  Algoritmo di ordinamento.
1 Analisi ammortizzata Si considera il tempo richiesto per eseguire, nel caso pessimo, una intera sequenza di operazioni. Se le operazioni costose sono.
1 Ordinamento (Sorting) Input: Sequenza di n numeri Output: Permutazione π = tale che: a i 1  a i 2  ……  a i n Continuiamo a discutere il problema dell’ordinamento:
GLI ALGORITMI DI ORDINAMENTO
Algoritmi e Strutture Dati HeapSort. Select Sort: intuizioni L’algoritmo Select-Sort  scandisce tutti gli elementi dell’array a partire dall’ultimo elemento.
Algoritmi e Strutture Dati Università di Camerino Corso di Laurea in Informatica (12 CFU) I periodo didattico Emanuela Merelli
Transcript della presentazione:

Top STACK Top

Le operazioni fondamentali che si fanno sugli stack sono: riempimento e svuotamento. Questo implica che durante lo svolgimento del programma il numero di oggetti nello stack può cambiare. Per descrivere uno stack è sufficiente sapere quali sono gli oggetti (Items) nello stack e il loro numero (Top). STACK

OPERAZIONI SUGLI STACK In uno stack l’elemento inserito per ultimo viene estratto per primo (LIFO - Last In First Out). In uno stack occorrerrà solo conoscere il numero di oggetti (Top). Aggiungere ed eliminare oggetti. Items[ ] è un array in cui si collocano gli oggetti, Top il numero di oggetti, l’operazione di aggiungere oggetti si chiama push e quella di eliminare oggetti pop. Quando Top=0 allora lo stack è vuoto.

OPERAZIONI SUGLI STACK AGGIUNGERE Top  Top + 1 Items[Top]  Item ELIMINARE Top  Top - 1

DIMOSTRAZIONI PER INDUZIONE La dimostrazione per induzione è una tecnica per provare che un asserto S(n) vale per tutti gli interi n maggiori di un certo limite inferiore. Supposto vero l’asserto la dimostrazione consiste in: individuare un caso base, il minimo valore di n, diciamo k, per cui si dimostra l’asserto S(k) dimostrare il passo induttivo, cioè che per ogni n  k, dove S(k) è la base induttiva, S(n) implica S(n+1) o equivalentemente supposto vero S(n) dimostrare che è vero S(n+1). Esempio Vogliamo dimostrare che: caso base Poniamo n=0 avremo che è quindi dimostrato vero

Il membro sinistro può essere riscritto come Avendo supposto vero l’asserto Sostituiamo b) in a) a) b) passo induttivo Dobbiamo ora dimostrare che   c.v.d. b) Supposto sia vero

RICORSIVITA’ Algoritmo ricorsivo Un algoritmo è ricorsivo quando per trovare la soluzione ad un dato problema fa uso della soluzione trovata per lo stesso problema presentato in una versione più ridotta.

ESEMPIO Problema del Massimo Comun Divisore (MCD o GCD) Dati due numeri interi m ed n trovare il più grande intero positivo che divide sia m che n. Soluzioni possibili Scomposizione in fattori primi Algoritmo di Euclide

ALGORITMO DI EUCLIDE PER IL MASSIMO COMUN DIVISORE (  300 A.C.) Siano m ed n due numeri naturali e supponiamo sia m>n 1Si divide m per n 2Se il resto è zero allora n è il MCD tra m e n. 3Se il resto è diverso da zero torna al primo passo scambiando m con n e n con r (cioè dividi n per r)

N R R R’ M MCD= R’ ALGORITMO DI EUCLIDE

Pseudo codice IF M o N sono valori che rappresentano una soluzione valida THEN GCD  valore della soluzione (M o N) ELSE GCD  GCD(N, M MOD N)

PROGRAM Euclide; VAR M,N:integer; BEGIN writeln('Assegna M e N '); read(M);read(N); writeln('Il MCD e'':= ',MCD(M,N)); readln END. FUNCTION MCD(M,N:integer):integer; VAR Resto:integer; BEGIN Resto:=M MOD N; WHILE Resto<>0 DO BEGIN M:=N; N:=Resto; Resto:=M MOD N END; MCD:=N END; FUNCTION GCD(M,N:integer):integer; BEGIN IF N=0 THEN GCD:=M ELSE GCD:=GCD(N,M MOD N) END; writeln('Il GCD e'':= ',GCD(M,N));

GCD(66,48) N=0? No GCD(48,18) GCD(18,12) N=0? No GCD(12,6) N=0? No GCD(6,0) N=0? No N=0? Si GCD6 GCD(6,0) GCD FUNCTION GCD(M,N:integer):integer; BEGIN IF N=0 THEN GCD:=M ELSE BEGIN writeln(’**push** GCD(',M,',',N,')'); writeln; GCD:=GCD(N,M MOD N); writeln(’**pop** N= ',M MOD N) END END; GCD:=GCD(N, M MOD N)

GCD(30,18) N=0? No GCD(18,12) N=0? No GCD(12,6) N=0? No GCD(6,0) N=0? Si GCD6 GCD(6,0) GCD GCD:=GCD(N, M MOD N) FUNCTION GCD(M,N:integer):integer; BEGIN IF N=0 THEN GCD:=M ELSE GCD:=GCD(N,M MOD N); END; GCD(30,18) GCD(18,12) GCD(12,6) GCD(6,0) =6

Ogni algoritmo ricorsivo deve essere tale che durante i passi della ricorsione, cioè della riduzione del problema, si giunge sempre ad una soluzione. Questa soluzione è detta caso base o STOPPING CASE. Nel caso del GCD il caso base è il caso in cui N=0. Caso base : è una soluzione per un algoritmo ricorsivo per la quale non sono necessarie ulteriori chiamate ricorsive. Ogni algoritmo ricorsivo, per essere valido, richiede almeno un caso base. Il meccanismo di gestione delle chiamate ricorsive è quello dello stack, si fa cioè ricorso alla tecnica LIFO ed è chiamato Run-time stack.

Un esempio di ricorsione per accumulazione Problema Si vuole calcolare la potenza Nma del numero reale Xre. Soluzione Base Case Ricorsione FUNCTION PotenzaN(Xre:real,N:integer):real; BEGIN IF N=0 THEN PotenzaN :=1 ELSE PotenzaN:= Xre*PotenzaN(Xre,N-1); END;

PotenzaN(0.9,3) N=0? No PotenzaN(0.9,2) PotenzaN(0.9,1) N=0? No PotenzaN(0.9,0) PotenzaN(0.9,1) N=0? No N=0? Si PotenzaN 1 PotenzaN 0.9* PotenzaN(0.9,3) FUNCTION PotenzaN(Xre:real,N:integer):real; BEGIN IF N=0 THEN PotenzaN :=1 ELSE PotenzaN:= Xre*PotenzaN(Xre,N-1); END; 0.9*PotenzaN(0.9,3) 0.9*PotenzaN(0.9,2) 0.9*PotenzaN(0.9,1) 0.9*PotenzaN(0.9,0) =1 =0.9*1 =0.9*0.9 =0.9*0.9*0.9

DIMOSTRAZIONE PER INDUZIONE Vogliamo dimostrare che S(n): a) caso base Poniamo n=1 avremo che è quindi dimostrato vero Avendo supposto vero l’asserto sostituiamo in b) il valore che si ottiene da a) passo induttivo Dobbiamo ora dimostrare che b) q.e.d.

COME FUNZIONA LA RICORSIVITA’ PROCEDURE(p’ 1,…., p’ k ) caso base ? NO allora applica PROCEDURE(p” 1,…., p” k ) caso base ? NO allora applica PROCEDURE(p* 1,…., p* k ) caso base ? SI allora applica la soluzione a Applica la soluzione a PROCEDURE(p 1,…., p k ) caso base ? NO allora applica Applica la soluzione a Dove (p i 1,…., p i k ) sono problemi ridotti del problema precedente

IF i parametri fanno riferimento a un caso base THEN risolvi il problema ELSE usa i valori dei parametri per un problema ridotto CHIAMA LA PROCEDURA O FUNZIONE PER RISOLVERE IL PROBLEMA RIDOTTO Possiamo dire che è stato applicato il metodo del DIVIDE ET IMPERA

Un algoritmo iterativo consiste in un unico processo che ripete le stesse identiche operazioni molte volte. Un algoritmo ricorsivo consiste in un numero finito di processi aperti uno dopo l’altro e posti in uno stack. Non appena si chiude un processo subito si scende nello stack e si chiude il processo immediatemente seguente e così via di seguito.

Per scrivere un algoritmo ricorsivo bisogna soddisfare le seguenti condizioni: 1. Esiste almeno un caso base la cui soluzione è banale 2. Tutti i sottoproblemi devono poter essere risolti in termini di versioni ridotte di uno stesso problema 3. Le azioni applicate per la soluzione di un problema ridotto portano sempre alla soluzione di un problema più grande 4. In funzione di quanto sia grande il problema iniziale deve essere sempre possibile trovare almeno un caso base nel corso della elaborazione del problema originale.

FUNCTION Sum(N:integer):integer; BEGIN IF N=0 THEN Sum :=0 ELSE Sum :=N+ Sum(N-1) END; Sommatoria dei primi N interi positivi 1. La somma dei primi 0 interi positivi vale La somma dei primi N interi positivi è uguale alla somma dei primi N-1 interi più N. 5+ Sum(4) 2+Sum(1) 3+ Sum(2) 4+ Sum(3) Sum =15 1+ Sum(0) Sum =1Sum =3Sum =6Sum =10 Sia N=5

DIMOSTRAZIONE PER INDUZIONE Vogliamo dimostrare che S(n): a) caso base Poniamo n=1 avremo che è quindi dimostrato vero Possiamo scrivere q.e.d. passo induttivo Dobbiamo ora dimostrare che b)

Quando si applica un processo ricorsivo tipo quello della accumulazione bisogna assicurarsi che i valori accumulati nelle relative variabili siano correttamente passati da un processo all’altro. Inoltre il valore assunto da una variabile in un processo ricorsivo non deve essere distrutto dal lancio di un altro processo ricorsivo. Di qui la necessità di passare le variabili utilizzando la chiamata per VAR. Esempio: Fare la somma dei primi N interi positivi e mostrare le somme parziali ogni M passi. Pseudo-codice IF N=0 THEN scrivi un messaggio Sum  0 ELSE ShowSums(N-1, M, Sum) Sum  Sum +N IF N MOD M=0 THEN scrivi N e Sum

PROGRAM SommaRicorsiva(input,output); VAR Nin,Min,Sumout:integer; PROCEDURE ShowSums(N,M:integer; VAR Sum:integer); VAR Temp:integer; BEGIN IF N=0 THEN BEGIN Sum:=0 END ELSE BEGIN ShowSums(N-1,M,Sum); Sum:=Sum+N; Temp:=N MOD M; IF N MOD M=0 THEN writeln('La somma dei primi ',N:1,' numeri e'' = ',Sum:1,'.') END END; BEGIN writeln(' Assegna N e M '); readln(Nin); readln(Min); writeln(' N M Sum'); ShowSums (Nin,Min,Sumout); writeln('La somma dei primi ',Nin:1,' numeri e'' = ', Sumout:1,'.'); END.

Assegna N e M 7 2 N M Sum push** push** push** push** push** push** push** Somme parziali pop** pop** La somma dei primi 2 numeri e' = 3. pop** pop** La somma dei primi 4 numeri e' = 10. pop** pop** La somma dei primi 6 numeri e' = 21. pop** La somma dei primi 7 numeri e' = 28.

ESERCIZIO Sia dato un vettore A di interi di dimensione N, scrivere una funzione ricorsiva che restituisca la somma di tutti gli elementi di A. Sia dato un vettore A di interi di dimensione N, scrivere una procedura ricorsiva che restituisca la somma di tutti gli elementi pari di A e la somma di tutti gli elementi dispari di A.

Un algoritmo ricorsivo deve essere completo, deve cioè sempre esistere una soluzione qualunque sia l’input. La completezza dipende dal dominio su cui si definisce l’algoritmo. Esempio: PotenzaN se definito sugli interi non è completo perché non funziona per gli interi negativi (infatti N-1 per N negativo non raggiunge mai lo 0). Diventa completo se il domino di definizione è quello dei numeri interi positivi. Stack Infinito Si genera quando per un qualche input di un algoritmo ricorsivo non si raggiunge mai il caso base.

Esempio Dato un testo scritto su un file e formato da più righe leggerlo e riscriverlo in ordine inverso rispetto alle righe. Es. La Vispa Teresa avea tra l’erbetta a volo sorpresa gentil farfalletta a volo sorpresa avea tra l’erbetta La Vispa Teresa Pseudo-codice reset(Teresa) InvertiRighe (Teresa)

PROCEDURE MostraRigheInvertite (VAR Teresa:text); BEGIN StoreDisplay(Teresa) END; PROGRAM InvertiRighe(Teresa,output); VAR Teresa:text; PROCEDURE StoreDisplay(VAR Teresa:text); {procedura ricorsiva: la prima linea letta è l’ultima mostrata a video} BEGIN ……….. END; { BODY } BEGIN reset(Teresa); MostraRigheInvertite END.

*push* La vispa Teresa *push* avea tra l'erbetta *push* a volo sorpresa *push* gentil Farfalletta *pop* gentil Farfalletta *pop* a volo sorpresa *pop* avea tra l'erbetta *pop* La vispa Teresa PROGRAM InvertiRighe(output,FInput); CONST LungMax=80; {massima lunghezza permessa alle stringhe } TYPE Stringa=STRING[LungMax]; VAR FInput: text; PROCEDURE StoreDisplay(VAR FInput:text); VAR Rigo: Stringa; BEGIN IF NOT eof(FInput) THEN BEGIN readln(FInput,Rigo); writeln('*push* ',Rigo); StoreDisplay(FInput); writeln(' *pop* ',Rigo) END END; {BODY } BEGIN assign(FInput,'C:\TP\ESEMPI\TERESA.TXT'); reset(FInput); StoreDisplay(FInput); readln END. Caso base

GCD:=GCD(N, M MOD N) GCD(30,18) N=0? No GCD(18,12) N=0? No GCD(12,6) N=0? No GCD(6,0) N=0? Si GCD6 GCD(6,0) GCD FUNCTION GCD(M,N:integer):integer; BEGIN IF N=0 THEN GCD:=M ELSE GCD:=GCD(N,M MOD N); END; GCD(30,18) GCD(18,12) GCD(12,6) GCD(6,0) =6

caso base Poniamo GCD(M,0)=M passo induttivo Dobbiamo ora dimostrare che GCD(M’,N’)=GCD(N, M MOD N) DIMOSTRAZIONE PER INDUZIONE DELLA CORRETTEZZA DELL’ALGORTIMO RICORSIVO PER IL GCD Supponiamo GCD(M’,N’)=X allora M’=hX e N’=zXdove h e z sono interi essendo N’=M MOD N questo implica per definizione che M=kN+N’ dove k è un intero ma N’=zX allora M=kN+zXinoltre N=M’=hX quindi M=khX+zX=(kh+z)X=wX essendo allora sia M che N divisibili per X questo è il GCD(M,N)

ESERCIZIO Sia dato un vettore A di interi di dimensione N, scrivere una funzione ricorsiva che restituisca la somma di tutti gli elementi di A. Sia dato un vettore A di interi di dimensione N, scrivere una procedura ricorsiva che restituisca la somma di tutti gli elementi pari di A e la somma di tutti gli elementi dispari di A. esercizi

ALTRI ESEMPI Supponiamo di avere 3 lettere a b c. Vogliamo sapere quante permutazioni si possono fare con questi 3 caratteri. - ci sono 3 maniere per scegliere quale lettera mettere in terza posizione (genericamente n) abc acb cba - per ognuna delle 3 scelte precedenti ci sono 2 maniere diverse per scegliere la lettere da mettere in seconda posizione in totale 3*2 (genericamente n*(n-1)) abc bac acb cab cbabca - per ognuna delle 6 scelte precedenti c’è 1 sola maniera per scegliere la lettere da mettere in prima posizione in totale 3*2*1 (genericamente n*(n-1)…..*1) abc bac acb cab cbabca FATTORIALE

FUNCTION Fattoriale(N:integer):integer; VAR Count, Product: integer; BEGIN Product:=1; FOR Count:=2 TO N DO Product:=Product*Count; Fattoriale:=Product END; FUNCTION Fattoriale (N:integer):integer; BEGIN IF N=0 THEN Fattoriale:=1 ELSE Fattoriale:=N*Fattoriale(N-1) END;

Dato un vettore di interi scrivere una procedura ricorsiva che trovi il valore del numero più grande in esso contenuto esercizi

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM determinare, con una procedura ricorsiva, il valore massimo in ciascuna delle due diagonali principali.} {******** MAIN************} N:=5; ScriviMatrice(A,N); Diagona(N,N,A,M1,M2); writeln(' I Massimi sono ', M1,' e ',M2); readln END. TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N, M1,M2:integer; PROCEDURE Diagona(Niniz,N1:integer;VAR A1:arrayx;VAR MD1,MD2:integer); {Scorri a partire dal basso ricorsivamente la matrice. Seleziona nelle due diagonali gli elementi più grandi} VAR N2,N3:integer; BEGIN IF N1=0 THEN BEGIN MD1:=0; MD2:=0; END ELSE BEGIN Diagona(Niniz,N1-1,A1,MD1,MD2); IF A1[N1,N1]>MD1 THEN MD1:= A1[N1,N1]; IF A1[N1,Niniz-N1+1]>MD2 THEN MD2:= A1[N1,Niniz-N1+1]; END;

FUNCTION Diagona(Niniz,N1:integer;VAR A1:arrayx;VAR MD1,MD2:integer):integer; {Scorri a partire dal basso ricorsivamente la matrice. Seleziona nelle due diagonali gli elementi più grandi e di questi stampa il maggiore} VAR N2,N3:integer; BEGIN IF N1=0 THEN BEGIN MD1:=0; MD2:=0; END ELSE BEGIN Diagona:=Diagona(Niniz,N1-1,A1,MD1,MD2); IF A1[N1,N1]>MD1 THEN MD1:= A1[N1,N1]; IF A1[N1,Niniz-N1+1]>MD2 THEN MD2:= A1[N1,Niniz-N1+1]; END; Diagona:=MD1; IF MD1 < MD2 Then Diagona:=MD2; END;.

Esempio con due casi base Problema: Assegnare agli elementi dell’Array di interi Ints, dei numeri compresi nell’intervallo 1..TotaleAssegnato. Ogni numero viene dato da tastiera. Il processo di lettura cessa o quando si introducono tutti i numeri concessi (MaxElements) oppure quando si introduce un numero negativo. Subito dopo si effettua l’assegnazione. In questo caso i casi base possibili sono due: abbiamo letto il massimo numero possibile di valori abbiamo letto un numero negativo In entrambi i casi la lettura deve terminare e si effettua l’assegnazione

Pseudo-Codice Inserisci(Left,TotaleAssegnato,Ints) {Indichiamo con Left quanti numeri positivi è ancora possibile assegnare e con Temp il valore letto } IF Left = 0 THEN gestisci il caso base N°1 ELSE read(Temp) IF Temp<=0 THEN gestisci il caso base N°2 ELSE Inserisci(Left-1,TotaleAssegnato,Ints) istruzioni dopo la ricorsione TotaleAssegnato = 0 TotaleAssegnato = TotaleAssegnato + 1 Ints[TotaleAssegnato ]  Temp Temp< = 0

PROGRAM CaseBase2(input,output); CONST MaxElements=4; TYPE IntsArray=ARRAY[1..MaxElements] OF integer; VAR Ints:IntsArray;Left, TotaleAssegnato, I:integer; PROCEDURE Inserisci(Left:integer; VAR TotaleAssegnato:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left=0 THEN BEGIN readln; writeln('Non possono essere letti altri valori. '); TotaleAssegnato:=0; END ELSE BEGIN read(Temp); IF Temp <=0 THEN BEGIN writeln('E'' stato introdotto un numero negativo. '); TotaleAssegnato:=0; END ELSE BEGIN Inserisci(Left-1, TotaleAssegnato,Ints); TotaleAssegnato:= TotaleAssegnato+1; Ints[TotaleAssegnato]:=Temp END END;

{BODY} BEGIN writeln('Inizia inserzione dati max= ',MaxElements); writeln; Inserisci(MaxElements,TotaleAssegnato,Ints); writeln(' ARRAY '); FOR I:=1 TO TotaleAssegnato DO writeln(Ints[I]); readln END. Inizia inserzione dati max= 4 Left TotaleAssegnato 1 push** push** push** push** 1 0 Non possono essere letti altri valori. pop** 1 0 pop** 2 1 pop** 3 2 pop** 4 3 ARRAY Inizia inserzione dati max= 4 Left TotaleAssegnato 11 push** push** E' stato introdotto un numero negativo. pop** 3 0 pop** 4 1 ARRAY 12 11

Alcuni suggerimenti Fatti importanti come si passano i valori dei parametri a-usare una chiamata per valore per determinare se il CASE BASE è verificato b-se il processo ricorsivo è di tipo per accumulazione usare la chiamata per VAR per la variabile di accumulazione c-usare una variabile locale se il suo valore è istanziato all’interno del processo ricorsivo per cui ad ogni passo della ricorsione riprende il valore di partenza PROCEDURE Inserisci(Left:integer; VAR TotaleAssegnato:integer; VAR Ints:IntsArray); VAR Temp: integer;

l’ordine con cui le istruzioni vengono eseguite, se prima o dopo la chiamata ricorsiva A-se una o più istruzioni riducono la dimensione del problema esse devono precedere la chiamata ricorsiva B-se una o più istruzioni necessitano del risultato della ricorsione vanno poste dopo la chiamata ricorsiva ElaboraTesto(Rigo) Pseudo codice IF Not eof(InFile) THEN readln(Finput,Rigo) ElaboraTesto(Rigo) BEGIN read(Temp); IF Temp <=0 THEN BEGIN writeln('E'' stato introdotto un numero negativo. '); TotaleAssegnato:=0; END ELSE BEGIN Inserisci(Left-1, TotaleAssegnato,Ints); TotaleAssegnato:= TotaleAssegnato+1; Ints[TotaleAssegnato]:=Temp END

PROCEDURE Inserisci2(Left:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left<>0 THEN BEGIN Inserisci(Left-1,Ints); read(Temp); Ints[Left]:=Temp END END; PROCEDURE Inserisci3(Left:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left<>0 THEN BEGIN read(Temp); Inserisci(Left-1,Ints); Ints[Left]:=Temp END END; Inserisci2 push** 5 push** 4 push** 3 push** 2 push** 1 pop** 1 10 pop** 2 20 pop** 3 30 pop** 4 40 pop** 5 50 ARRAY Inserisci3 push** 5 10 push** 4 20 push** 3 30 push** 2 40 push** 1 50 pop** 1 pop** 2 pop** 3 pop** 4 ARRAY

ESERCIZI

FUNCTION Sommatoria (N11,N22:integer):integer; BEGIN IF (N11=N22) THEN IF (N11 MOD 2)=0 THEN Sommatoria:=N22 ELSE Sommatoria:=0 ELSE IF (N22 MOD 2)=0 THEN Sommatoria :=N22+Sommatoria(N11,N22-1) ; ELSE Sommatoria := Sommatoria(N11,N22-1); END; ? ESERCIZI Sommare tutti gli interi pari compresi tra i numeri N1 ed N2 assegnati sopn1n2

ESERCIZI Sommare le seguenti espressioni per tutti gli interi compresi tra N1 ed N2 esercizi

1)Restituisca il minimo o il massimo in un vettore di interi; 2) Restituisca l’indice del minimo e/o del massimo; (funzione o procedura) 3) Trova la massima differenza in valore assoluto tra un elemento ed il precedente ( escluso il primo) Esercizi sui vettori. Scrivere una funzione e/o procedura ricorsiva che esercizi

Assegnato un vettore A di interi di lunghezza N ed un numero x, calcolare le occorrenze di x in A. Procedure occorre(A: vettore; i,x,N:integer; var conta:integer); Begin if i<=N then begin if a[i]=x then conta:=conta+1; occorre(A,i+1,x,N,conta); end; End; Consideriamo una procedura ricorsiva. Se non siamo giunti alla fine allora se A[i]=x allora incrementa un contatore richiama la procedura per un caso più semplice

PROCEDURE occorre(N,i,x:integer; var conta:integer; VAR A1:arrayx); Begin if i<=N then begin if a[i]=x then conta:=conta+1; occorre(N,i+1,x, conta,A1); end; End; FUNCTION occorrere(i,x1:integer; VAR A1:arrayx):integer; Begin if i=0 then occorrere:=0 ELSE if a[i]=x1 then occorrere:= occorrere(i-1,x1,A1)+1 ELSE occorrere:= occorrere(i-1,x1,A1); End;

SULLE MATRICI Come controlliamo ogni elemento della matrice? Partendo dalla riga=1 e colonna=1 possiamo procedere per linee orizzontali: quando la colonna arriva al valore n ( nell’esempio N=3) allora scatta alla riga successiva e la colonna diventa 1: Se j>N allora i=i+1 e j=1 Caso Base: se i>N allora siamo giunti alla fine della matrice senza incontrare errori: la matrice è unitaria; se durante il controllo trova che la condizione non è verificata deve ritornare il valore false Assegnata una matrice quadrata NxN, scrivere una funzione ricorsiva che restituisca true se la matrice è unitaria, false altrimenti

RICORSIONE SULLE MATRICI IF i>N THEN unitaria=true ELSE IF condizione NON vera THEN unitaria=false else IF j>N THEN unitaria=unitaria (a,i+1,1,N) ELSE unitaria=unitaria(a,i,j+1,N) Assegnata una matrice quadrata NxN, scrivere una funzione ricorsiva che restituisca true se la matrice è unitaria, false altrimenti Caso base: i>N Matrice unitaria Else è unitaria se altrimenti NON unitaria A[i,j]=1 se i=j A[i,j]=0 se i<>j

RICORSIONE SULLE MATRICI function unitaria(var a: matrice;i,j,n: integer): boolean; begin if (i>n) then unitaria:=true else if ((i=j) and (a[i,j]<>1)) or ((i<>j) and (a[i,j]<>0)) then unitaria:=false else if j>n then unitaria:=unitaria(a,i+1,1,n) else unitaria:=unitaria(a,i,j+1,n); end;

Esercizi sulle matrici 1)scrivere una funzione ricorsiva che restituisca true se è simmetrica, false altrimenti. 2)scrivere una procedura o funzione ricorsiva che restituisca il valore true se la matrice possiede due righe uguali, false altrimenti. 3)scrivere una procedura o funzione ricorsiva che calcoli la somma delle righe dispari e quelle delle righe pari 4)scrivere una funzione ricorsiva che restituisca true se tutti gli elementi della diagonale principale sono positivi 5)scrivere una procedura o funzione ricorsiva che controlli se la somma degli elementi della diagonale principale è uguale a quella della diagonale secondaria 6)scrivere una procedura o funzione ricorsiva che restituisca il valore true se ogni riga i-esima della matrice possiede un numero di i valori negativi, false altrimenti. Assegnata una matrice A di interi

Altri esercizi sulla ricorsione. Un caso base 1 - Assegnata una matrice MxM determinare, con una funzione ricorsiva, il valore massimo tra i massimi delle diagonali principali. Esempio Il valore massimo appartenente alla prima diagonale principale è 10 in A[3,3] Il valore massimo appartenente alla seconda diagonale principale è 8 in A[3,1] Il valore massimo cercato è quindi 10 in A[3,3]. 2 - Assegnato un file di testo con stringhe lunghe N per ogni rigo, determinare quante sono le occorrenze di un carattere preassegnato con una funzione ricorsiva. Esempio Cercare le occorrenze di ‘e’ nel seguente testo: La Vispa Teresa Avea tra l’erbetta A volo sorpresa Gentile farfalletta ‘e’ ricorre 9 volte

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM determinare, con una funzione ricorsiva, se la somma delle due diagonali sono uguali.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,i1,M1,M2:integer; esercizi

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM determinare, con una funzione ricorsiva, se ci sono due righe uguali.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,i1,j1:integer; esercizi

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM determinare, con una funzione ricorsiva, il valore massimo tra i massimi delle diagonali principali.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,i1,tem:integer; esercizi

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM, con una funzione ricorsiva, Controlla che in ogni riga i ci sono giusto “ i” numeri negativi.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,i1,j1,conta:integer; esercizi

PROGRAM Diagonale(input,output); { Assegnata una matrice MxM determinare, con una funzione ricorsiva, se è simmetrica.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,i1,j1:integer; esercizi

Ricorsione non lineare = più di una chiamata ricorsiva per blocco Per capire bene come opera una ricorsione non lineare si traccia un albero che mostra la storia dello stack. Ricorsione lineare = al massimo una chiamata ricorsiva per blocco

Esempio PROGRAM TreeExample; PROCEDURE C(N:integer); BEGIN IF N>0 THEN C(N-1) END; PROCEDURE B; BEGIN C(1) END; PROCEDURE A; BEGIN B END; {MAIN} BEGIN A; C(1); writeln(‘Fine’) END. PROCEDURE APROCEDURE BPROCEDURE C(1) PROCEDURE C(0) MAIN PROCEDURE C(1) PROCEDURE C(0)

main chiama A A chiama B B chiama C(1) C(1) chiama C(0) C(0) ritorna a C(1) C(1) ritorna a B B ritorna A A ritorna a main main chiama C(1) C(1) chiama C(0) C(0) ritorna a C(1) C(1) ritorna a main main chiama Fine Fine PROGRAM TreeExample(output); PROCEDURE C(N:integer); BEGIN IF N>0 THEN BEGIN writeln('C(',N,') chiama C(',N-1,')'); C(N-1); writeln(' C(',N-1,') ritorna a C(',N,')') END END; PROCEDURE B; BEGIN writeln('B chiama C(1)'); C(1); writeln(' C(1) ritorna a B') END; PROCEDURE A; BEGIN writeln('A chiama B'); B; writeln('B ritorna A') END; BEGIN writeln('main chiama A'); A; writeln('A ritorna a main'); writeln('main chiama C(1)'); C(1); writeln('C(1) ritorna a main'); writeln('main chiama Fine'); writeln('Fine'); readln END.

mainC(0) ritorna a C(1) C(1) ritorna a BB ritorna A A ritorna a main C(1) ritorna a mainC(0) ritorna a C(1) main chiama A A A chiama B B B chiama C(1) C(1) C(1) chiama C(0) C(0) Fine ritorna a main main chiama C(1) C(1) C(1) chiama C(0) C(0) main chiama Fine writeln

C(0) main A B C(1) C(0) writeln Esempio PROGRAM TreeExample; PROCEDURE C(N:integer); BEGIN IF N>0 THEN C(N-1) END; PROCEDURE B; BEGIN C(1) END; PROCEDURE A; BEGIN B END; {MAIN} BEGIN A; C(1); writeln(‘Fine’) END.

Regole per costruire l’albero della storia dello stack 1. Ogni albero deve avere una radice principale 2. L’albero è fatto di nodi che rappresentano i processi che sono eseguiti ad un certo passo. Ogni nodo rappresenta esattamente un processo. Se è necessario si mettono etichette che indicano il processo. 3. Un ramo dell’albero rappresenta una chiamata e un ritorno di un processo rispetto ad un altro. Se ci sono più processi ricorsivi si indicano in ordine a partire da sinistra. 4. Ogni nodo è visitato una sola volta (push e pop) e nessun processo può terminare se prima non sono terminati tutti quelli che ha chiamato.

Problema Nel 1228 messer Leonardo Pisano si pose il seguente problema: posta una coppia di conigli in un recinto supponiamo che questa coppia dopo un mese genera un’altra coppia, questa a sua volta dopo un altro mese ne genera un’altra e contemporaneamente anche le precedenti generano altre coppie. Dopo un anno, cioè dopo 12 mesi quanti conigli ci saranno nel recinto? 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233

Esempio I numeri di Fibonacci definiti ricorsivamente. N=1 :Fib(N)  1 N=0 :Fib(N)  0 N>=2 :Fib(N)  Fib(N-2)+FIB(N-1) FUNCTION Fibonacci(N:integer):integer; {ritorna l’N-esimo numero di Fibonacci} BEGIN IF N=0 THEN Fibonacci:=0 ELSE IF N=1 THEN Fibonacci:=1 ELSE Fibonacci:= Fibonacci(N-2) + Fibonacci(N-1) END.

Ricorsione lineare: al più una chiamata ricorsiva nell’ambito di uno stesso processo ricorsivo. Ricorsione non lineare: più di una chiamata ricorsiva nell’ambito di uno stesso processo ricorsivo. main F(3) F(1) F(2) F(4) F(2) Fibonacci(4) F(1)F(0) F(1)F(0) main F(3) F(1)F(2) F(1)F(0) Fibonacci(3) FUNCTION Fibonacci(N:integer):integer; BEGIN IF N=0 THEN Fibonacci:=0 ELSE IF N=1 THEN Fibonacci:=1 ELSE Fibonacci:= Fibonacci(N-2) + Fibonacci(N-1) END.

Fibonacci(6) F(6) F(5)F(4) + F(2) F(3) + F(2) F(1) + F(0)F(1) F(3) + F(0)F(1) F(3) F(1) F(2) F(4) F(5) F(3) F(6) F(1)F(2) F(3) F(4) F(2) F(0)F(1) F(0) F(1) F(0)F(1) F(0) F(1) fibon1

Complessità dell’algoritmo per il calcolo dei numeri di Fibonacci E’ stato dimostrato che per N abbastanza grande la complessità di F(N), cioè il numero di chiamate ricorsive, è circa O(1.61 N ) N1,61^N1 MFLOP 1 TERAFLOP ,01sec ,13minuti ,10ore anni ,45348E+27anni7,45E+24

PROGRAM ContaCall(output); VAR Calls:real; No:integer; FUNCTION Fibonacci(N:integer; VAR Calls:real):real; {ritorna l'N-esimo numero di Fibonacci} BEGIN Calls:=Calls+1; IF N=0 THEN Fibonacci:=0 ELSE IF N=1 THEN Fibonacci:=1 ELSE Fibonacci:= Fibonacci(N-2,Calls) + Fibonacci(N-1,Calls) END; {BODY} BEGIN FOR No:=1 TO 40 DO BEGIN Calls:=0; IF No MOD 5=0 THEN writeln('Fibonacci(',No:1,') = ', Fibonacci(No,Calls):20:0,' chiamate= ',Calls:20:0) END; readln END.

Fibonacci(5) = 3 chiamate= 9 Fibonacci(10) = 34 chiamate= 109 Fibonacci(15) = 377 chiamate= 1219 Fibonacci(20) = 4181 chiamate= Fibonacci(25) = chiamate= Fibonacci(30) = chiamate= Fibonacci(35) = chiamate= Fibonacci(40) = chiamate= fibon

Per ridurre da O (1.61 N ) a O(N) la complessità di calcolo per i numeri di Fibonacci invece di chiamare ricorsivamente la procedura di calcolo per ogni nodo dell’albero dello stack depositiamo i risultati di ogni computazione in un array e li richiamiamo, senza più calcolarli ogni volta che ne abbiamo bisogno. Detto FibNos l’array in cui si depositano i numeri parziali possiamo costruire una procedura ricorsiva alla seguente maniera: caso base Quando N=2 allora poni FibNos[2]  1 FibNos[1]  0 CHIAMATA RICORSIVA FibNos[N]  FibNos[N-2] +FibNos[N-1]

Pseudo Codice SetFibNo(N:integer; VAR FibNos:FibNoArr); IF N=2 THEN BEGIN FibNos[2]:=1; FibNos[1]:=1 END ELSE BEGIN SetFibNo(N-1,FibNos); FibNos[N]:=FibNos[N-2] + FibNos[N-1] Svantaggio Siamo limitati dalla dimensione dell’array per determinare N massimo

PROGRAM ContaCallVeloce(output); {calcola l'N-esimo numero di Fibonacci in O(N) } CONST MaxFib=50; TYPE FibNoArr=ARRAY[1..MaxFib] OF real; VAR FibNos:FibNoArr; VAR No:integer; PROCEDURE SetFibNo(N:integer; VAR FibNos:FibNoArr); {ritorna l'N-esimo numero di Fibonacci} BEGIN IF N=2 THEN BEGIN FibNos[2]:=1; FibNos[1]:=1 END ELSE BEGIN SetFibNo(N-1,FibNos); FibNos[N]:=FibNos[N-2] + FibNos[N-1] END END; {BODY} BEGIN FOR No:=1 TO 40 DO BEGIN IF No MOD 5=0 THEN BEGIN SetFibNo(No,FibNos); writeln('Fibonacci(',No:1,') = ',No,FibNos[No]:20:0) END END; readln END. SetFibNo(4) SetFibNo(3) SetFibNo(2) F(3) F(1) F(2) F(4) F(2) FibNo[4] FibNo[3] FibNo[2] FibNo[1] fibona

Esercizio 1- Assegnato un intero N, calcolare il rapporto tra le coppie di numeri di Fibonacci F(n+1)/F(n) e per ogni coppia sottrarre a detto rapporto la radice positiva dell’equazione x 2 -x-1=0. 2- Calcolare il MCD tra la somma dei numeri di Fibonacci compresi tra 1 e 10 e quelli compresi tra 11 e 20 compresi tra 11 e 20 e quelli compresi tra 21 e 30 compresi tra 21 e 30 e quelli compresi tra 31 e 40 Testo consigliato da leggere MARIO LIVIO – La sezione aurea

Calcolare con una funzione ricorsiva l’N-esimo termine della successione seguente a1=3 a2=1 a3=-1 a n =a n-1 *a n-2 -(a n-3 +a n-1 +a n-2 ) Caso base N=1 -> S(1)=3, S(2)=1, S(3)=-1 Chiamata ricorsiva -> S(N):=S(N-1)*S(N-2)-(S(N-3)+S(N-1)+S(N-2)) ESERCIZIO

FUNCTION Success(A1,A2,A3:real;N:integer):real; {ritorna l'N-esimo valore di una successione} BEGIN IF N=1 THEN Success:=A1 ELSE IF N=2 THEN Success:=A2 ELSE IF N=3 THEN Success:=A3 ELSE BEGIN Success:= Success(A1,A2,A3,N-1)* Success(A1,A2,A3,N-2)- (Success(A1,A2,A3,N-3)+ Success(A1,A2,A3,N-1)+Success(A1,A2,A3,N-2)); END; ESERCIZIO Tracciare l’albero di ricorsione per A1=1; A2=2; A3=3 e N=7

ALGORITMI DI RICERCA LINEARE Problema: Cercare tra i valori contenuti in un Array un preassegnato valore. Esempio: Data una lista di N numeri verificare se esiste un preassegnato Valore. Condizioni di uscita: - la ricerca è finita se nessun elemento uguale a quello cercato esiste - la ricerca è finita se almeno un elemento uguale a quello cercato è stato trovato Partire dall’ultimo elemento della lista e risalire fino in cima nella ricerca dell’elemento.

Soluzione: Gestire opportunamente l’indice dell’array in cui sono contenuti gli elementi su cui fare la ricerca. I criteri per stabilire il nuovo valore da attribuire all’indice possono essere i più diversi. E’ però importante che una volta stabilito che un elemento individuato da un certo indice non è quello cercato questo elemento non venga più esaminato. Algoritmo 10.2 Indice  NumeroTotaleElementi Trovato  false WHILE NOT (Indice=0) AND NOT Trovato DO IF UnArray[Indice]= ValoreCercato Trovato  true ELSE Indice  Indice-1

Poiché ad ogni passo della ricerca eliminiamo un elemento il massimo numero di passi è pari al numero di elementi. Indicatore:=CercaIndice(Nome, NumeroElementi,ValoreCercato); IF Indicatore<>0 THEN BEGIN write(ValoreCercato,’ è stato trovato nella posizione ‘,Indicatore:2); END ELSE write(ValoreCercato,’ non è stato trovato ‘);

FUNCTION CercaIndice(VAR Nome: NomeArray; NumeroElementi:integer; ValoreCercato:NomeStringa):integer; VAR Indice:integer; Trovato: boolean; BEGIN WHILE NOT (Indice=0) AND NOT Trovato DO IF Nome[Indice]=ValoreCercato THEN Trovato:= true ELSE Indice:= Indice-1; CercaIndice:= Indice END.

Ricerca ricorsiva Pseudo codice FUNCTION Indice (VAR UnArray; Chiave; SubRange):IType IF terminato THEN Indice  0 ELSE prendi un Candidato IF UnArray[Candidato] = Chiave THEN Indice  Candidato ELSE rivedi il SubRange riducendo le dimensioni del problema Indice  Indice(UnArray, Chiave, SubRangeRidotto) Indice  Indice(UnArray, Chiave, SubRangeIniziale) ESPRESSIONE RICORSIVAcaso base 2 caso base 1

Caratteristiche di una ricerca ricorsiva Gli array passati al blocco ricorsivo vengono chiamati per VAR. Una chiamata ricorsiva implica sempre una riduzione del sub range di possibili candidati. Quindi nell’intestazione è presente almeno un parametro che rappresenta il subrange di elementi. Il valore del parametro in ogni istante di computazione è funzione di un qualche subrange candidato locale. Questa espressione i cui valori devono rappresentare una riduzione del subrange candidato viene calcolata e al successivo processo di ricerca i valori vengono applicati. La condizione di terminazione è espressa in termini dei parametri del subrange candidato. Questa condizione rappresenta il caso base quando non restano altri subrange candidati alla ricerca. L’altro caso base si ha quando la ricerca ha buon esito, quando cioè Array[Candidate] coincide con Chiave.

Esercizio Dato un Array del tipo FIGLIO PADRE MADRE aldo giulio maria giulio carlo anna carlo bruno pina ugo luca giulio maria ugo carla Scrivere un programma che con tre funzioni ricorsive dica: 1 - Dato X chi è il padre e la madre di X 2 - Dati X e Y determini se X è figlio di Y per parte di padre 3 - Dati X e Y determini se X è nonno o nonna di Y

figliopadremadre aldogiuliomaria giuliocarloanna carlobrunopina ugolucagiulio mariaugocarla {MAIN} BEGIN writeln('Dammi figlio ');readln(X); writeln('Il padre di ',X,' è ',CercaAvo(F,X, Nfamiglie,I1,padre)); writeln('La madre di ',X,' è ',CercaAvo(F,X, Nfamiglie,I1,madre)); END; PROGRAM Famiglia(output); {calcola le parentele } TYPE string30=STRING[30]; genitori=(figlio,padre,madre,nessuno); Typearr=ARRAY[1..10,genitori] OF string30; VAR A1:TypeArr; N1,Nfamiglie,I,J,I1,J1:integer; X,Y:string30; FUNCTION CercaAvo(VAR A:Typearr;X:string30;Nfam,I:integer;avo:genitori):string30; {determina chi è il padre di X} BEGIN IF i>Nfam THEN CercaAvo:='ignoto' ELSE IF (A[I,figlio]=X) THEN CercaAvo:=A[I,avo] ELSE CercaAvo:=CercaAvo(A,X, Nfam,I+1,avo) END;

figliopadremadre aldogiuliomaria giuliocarloanna carlobrunopina ugolucagiulio mariaugocarla {MAIN} BEGIN writeln('Dammi padre ');readln(X); writeln('Dammi figlio ');readln(Y); writeln(X,' padre di ',Y,' è ',VerificaPadre(F,X,Y, Nfamiglie,I1)); END; PROGRAM Famiglia(output); {calcola le parentele } TYPE string30=STRING[30]; genitori=(figlio,padre,madre,nessuno); Typearr=ARRAY[1..10,genitori] OF string30; VAR A1:TypeArr; N1,Nfamiglie,I,J,I1,J1:integer; X,Y:string30; FUNCTION VerificaPadre(VAR A:Typearr;XP,YF:string30;M,I:integer):boolean; {determina chi è il padre di X} BEGIN IF i>M THEN VerificaPadre:=FALSE ELSE IF (A[I,figlio]=YF) AND (A[I,padre]=XP) THEN VerificaPadre:=TRUE ELSE VerificaPadre:= VerificaPadre (A,XP,YF,M,I+1) END;

Una funzione di Search lineare può essere del tipo Linear(UnArray, Chiave, TotalElements) dove si presuppone che il subrange di candidati sia tra 1.. TotalElements. Esempio Supponiamo di avere un Array di stringhe Studenti, in cui si riportano gli studenti per MATRICOLA. Su questo array vogliamo fare delle ricerche. Una chiamata di funzione tipica è Indice:=Linear(Studenti, MatrCercata, N) FUNCTION Linear (VAR Studenti: Stinga; MatrCercata;Stringa; N :integer):integer; BEGIN IF N=0 THEN Linear:= 0 ELSEIF Studenti[N]=MatrCercata THEN Linear:=N ELSE Linear:=Linear(Studenti; MatrCercata; N-1) END; ESPRESSIONE RICORSIVA caso base 2caso base 1 RICERCA LINEARE

RICERCA BINARIA Data una lista di N elementi ordinati cercare se tra essi esiste un determinato elemento. Dividiamo gli elementi ordinati in due parti. Quello che cerchiamo può appartenere o alla prima o alla seconda parte, essendo tutti gli elementi ordinati. Dividiamo la parte scelta ancora in due e applichiamo ancora il ragionamento precedente. L’algoritmo termina o quando l’ultimo elemento rimasto dalle successive suddivisioni è uguale a quello cercato, oppure quando l’intervallo rimasto non è più suddivisibile il che implica che il nostro elemento non appartiene alla lista.

Basso  1 Alto  ElementiTotali WHILE NOT (Basso<=Alto) DO Metà  (Basso+Alto) DIV 2 IF Interi[Metà ]< ValoreCercato THEN Basso  Metà+1 ELSE Alto  Metà-1 IF Alto<= ElementiTotali THEN IF Interi[Basso]=Valore Cercato THEN Indice  Basso ELSE Indice  0 ELSE Indice  0

Una funzione di Search binario ha bisogno di due parametri per individuare il subrange: Lo e Hi. L’indice candidato per la nuova ricerca è dato da: Mid  (Lo+Hi) DIV 2 1° caso base è dato quando Lo>Hi 2° caso base è dato quando l’elemento cercato è stato trovato La chiamata iniziale è del tipo Binary(UnArray, Chiave, 1, TotalElements)

Pseudo Codice FUNCTION Binary(VAR UnArray; Chiave; Lo, Hi):TipoIndice; IF Lo>Hi THEN Binary  0 ELSE Mid  (Lo+Hi) DIV 2 IF UnArray[Mid]=Chiave THEN Binary  Mid ELSE IF UnArray[Mid]<Chiave THEN Binary  Binary(UnArray, Chiave, Mid+1, Hi) ELSE Binary  Binary(UnArray, Chiave, Lo, Mid-1) Binary  Binary(UnArray, Chiave, 1, UltimoElemento)

Problema Scrivere una funzione ricorsiva che ritorna vero se gli elementi di UnArray di interi, con valori assegnati nel subrange 1..TotElem, sono in ordine crescente. Obiettivo ricerca un elemento che sia fuori ordine in un dato subrange. Riduciamo di volta in volta il subrange fino a quando in questo resta un solo elemento allora vuol dire che la ricerca è finita e la risposta è TRUE. Se invece si verifica che è vera l’espressione UnArray[N-1]>UnArray[N] questo significa che è stato trovato un elemento non in ordine e la funzione ritorna FALSE.

FUNCTION Ordinato(VAR UnArray:IntsArray; N:integer):boolean; BEGIN IF N=1 THEN Ordinato:= TRUE ELSE IF UnArray[N-1] > UnArray[N] THEN Ordinato:= FALSE ELSE Ordinato:=Ordinato(UnArray,N-1)

FUNCTION Minimo(VAR UnArray:IntsArray; Candidato,N:integer):integer; BEGIN IF N=0 THEN Minimo:= Candidato ELSE IF UnArray[N] < UnArray[Candidato] THEN Minimo:= Minimo(UnArray, N, N-1) ELSE Minimo:= Minimo(UnArray,Candidato,N-1) Dato un Array di interi cercare in quale posizione si trova il numero più piccolo. Iniziamo con l’ipotesi che l’ultimo elemento dell’Array sia il minimo e ricorsivamente risaliamo l’array.

ESERCIZIO Scrivere un algoritmo ricorsivo per il calcolo della funzione booleana tale che assegnate due stringhe Sl e S2 restituisca TRUE se la seconda è contenuta tutta o in parte nella prima. FALSE altrimenti. Esempio: Se Sl=‘Smacchiare’ e S2=‘Macchia’ allora la funzione vale TRUE. Se Sl='Mentecatto' e S2=’tatto' allora la funzione vale FALSE

MERGE - SORT Un algoritmo di sort classico ha in genere una complessità di calcolo pari a O(N 2 ). Vediamo un algoritmo che, fondato sul criterio del DIVIDE ET IMPERA, ha una complessità più bassa. Il merge-sort è fondato sul principio ricorsivo di ridurre il problema di partenza di un fattore 2 e nessun processo ricorsivo attivato viene fatto più di una volta.

Complessità del MERGE-SORT I nodi dell’albero di sort sono log N. Per ogni nodo si fa un sort in i*N/i passi dove i rappresenta la profondità del nodo iN° passi 11*N 22*N/2 44*N/4 88*N/8 jj*N/j …….. log Nlog N*N/log N totale N*log N

Pseudo codice PROCEDURE SortIt(Lo,Hi:IType; VAR AnArray:ArrayType); usa i valori degli indici in input (Lo,Hi) per dividere AnArray in due subarray (inferiore e superiore) IF gli indici del subarray inferiore implicano un array ordinabile THEN SortIt(usa come indici quelli del subarray inferiore,AnArray) IF gli indici del subarray superiore implicano un array ordinabile THEN SortIt(usa come indici quelli del subarray superiore,AnArray) SortIt(1, TotalElement, AnArray)

Si parte con la richiesta di ordinare gli elementi dell’array compresi tra 1 e TotalElement, si riduce poi questo intervallo attraverso Lo e Hi fino a quando nel subarray non resta che un elemento. Questo è ovviamente ordinato e quindi si attiva la catena pop. Per dividere i Subarrays usiamo una variabile locale Mid. Questi Subarrays saranno prima ordinati (sorted) o poi (fusi) merged. CASO BASE si ha quando i due subarrays sono ridotti ad una sola variabile cioè sono banalmente ordinati. Quando si arriva al Caso Base allora si attiva il processo di Merge tra i due arrays adiacenti rimasti. Se invece siamo in presenza di subarrays con più di un elemento questo implica che il subarray deve essere ordinato.

Sort(7,8) Sort(5,6) Sort(5,8) Sort(3,4) Sort(1,2) Sort(1,4) Sort(1,8)

PROGRAM Mergesort(output,Infile); CONST Lo=1; Hi=8; TYPE TipoArr=ARRAY[1..8] OF integer; VAR AnArray:TipoArr; I, Mid:integer; PROCEDURE SortIt(Lo, Hi: integer; VAR AnArray:TipoArr); VAR Mid:integer; BEGIN Mid:=(Lo+Hi) DIV 2; IF Lo < Mid THEN SortIt(Lo,Mid,AnArray); IF Mid+1 < Hi THEN BEGIN SortIt(Mid+1,Hi,AnArray); END; Merge(Lo,Mid,Hi,AnArray); END; PROCEDURE Merge(Lo, Mid, Hi: integer; VAR AnArray:TipoArr); VAR Temp: TipoArr; Index, Index1, Index2 :integer; BEGIN Index1:=Lo; Index2:=Mid+1; FOR Index:=Lo TO Hi DO BEGIN IF Index1 > Mid THEN BEGIN Update(AnArray, Index2, Temp[Index]); END ELSE IF Index2 > Hi THEN Update(AnArray, Index1, Temp[Index]); ELSE IF AnArray[Index1] < AnArray[Index2] THEN BEGIN Update(AnArray, Index1, Temp[Index]); END ELSE Update(AnArray, Index2, Temp[Index]); END; FOR Index:=Lo TO Hi DO AnArray[Index]:=Temp[Index]; FOR Index:=Lo TO Hi DO write(AnArray[Index]:3); writeln; END; PROCEDURE Update(VAR AnArray:TipoArr; VAR CandidateIndex:integer; VAR NewElement:integer); BEGIN NewElement:=AnArray[CandidateIndex]; CandidateIndex:=CandidateIndex+1 END; { ******** MAIN *******} BEGIN SortIt(Lo,Hi,AnArray); END.

PROCEDURE Merge(Lo, Mid, Hi: integer; VAR AnArray:ArrayType); BEGIN END; PROCEDURE SortIt(Lo, Hi: integer; VAR AnArray:ArrayType); VAR Mid:integer; BEGIN Mid:=(Lo+Hi) DIV 2; IF Lo<Mid THEN SortIt(Lo, Mid, AnArray) IF Mid+1 < Hi THEN SortIt(Mid+1, Hi, AnArray) Merge(Lo, Mid, Hi, AnArray) END;

Sort(1,2) Sort(1,4) Sort(1,8) Lo Mid Hi Mid+1 IF Lo < Mid THEN SortIt(Lo, Mid, AnArray) IF Mid+1 < Hi THEN SortIt(Mid+1, Hi, AnArray ) Mid  (Lo+Hi) DIV 2 merge Sort(5,8) 56 8 merge Sort(5,6) 56 5 Sort(7,8) 78 8 merge Sort(3,4) merge

Una maniera per verificare se la procedura SortIt funziona bene è quella di scrivere la procedura di merge, con le seguenti scritte di controllo. PROCEDURE Merge(Lo, Mid, Hi:integer; VAR AnArray:ArrayType) BEGIN write(‘Subrange del 1° Merge (‘,Lo:1,’..’,Mid:1,’)’); write(‘Subrange 2° Merge (‘,Mid+1:1,’..’,Hi:1,’)’); write(‘Subrange Ordinato (‘,Lo:1,’..’,Ni:1,’)’); END;

PROCEDURE Update(VAR AnArray:ArrayType; VAR CandidateI:integer; VAR NewElements:ElementType); BEGIN NewElement:=AnArray[CandidateI]; CandidateI:= CandidateI+1 END; PROCEDURE Merge(Lo, Mid, Hi: integer; VAR AnArray:ArrayType); VAR Temp: ArrayType; I, I1, I2 :integer; BEGIN I1:=Lo; I2:=Mid+1; FOR I:=Lo TO Hi IF I1 > Mid THEN Update(AnArray, I2, Temp[I]) ELSE IF I2 > Hi THEN Update(AnArray, I1, Temp[I]) ELSE IF AnArray[I1] < AnArray[I2] THEN Update(AnArray, I1, Temp[I]) ELSE Update(AnArray, I2, Temp[I]) FOR I:=Lo TO Hi DO AnArray[I]:=Temp[I] END;

I1=Lo I2=Mid+1 I=Lo I1>MidI2>Hi A(I1)<A(I2) A(I1)  T(I) T(I)  A(I2) I2  I2+1 I=Hi I=LoI=Hi UP(A,I2,T(I)) UP(A,I1,T(I)) T(I)  A(I1) I1  I1+1 UP(A,I1,T(I))UP(A,I2,T(I)) T(I)  A(I1) I1  I1+1 T(I)  A(I2) I2  I2+1 SI Se è stata controllata tutta la prima metà allora aggiungi diret - tamente la seconda Se è stata controllata tutta la seconda metà allora aggiungi direttamente la prima Inserisci l’elemento più piccolo e incrementa opportunamente l’indice

I1=Lo I2=Mid+1 I=Lo I1>MidI2>Hi A(I1)<A(I2) A(I1)  T(I) T(I)  A(I2) I2  I2+1 I=Hi I=LoI=Hi UP(A,I2,T(I)) UP(A,I1,T(I)) T(I)  A(I1) I1  I1+1 UP(A,I1,T(I))UP(A,I2,T(I)) T(I)  A(I1) I1  I1+1 T(I)  A(I2) I2  I A B D C I I1 I2 INCR. xx T(I) INCR. I1 2 C C D D D B B A Merge-Sort

Svantaggi del Merge-Sort Necessita di un vettore di appoggio Effettua gli spostamenti anche se il vettore di partenza è già ordinato

Esercizio La Torre di Hanoi. Dati tre pioli verticali e n dischi di dimensioni decrescenti infilati nel primo piolo trasferire tutti i dischi sul secondo piolo, in maniera da mantenere l’ordine decrescente, dal basso verso l’alto, adoperando un terzo piolo di appoggio. Algoritmo 1 - sposta i primi n-1 dischi dal piolo 0 al piolo 2 rispettando l’ordine 2 - sposta l’ultimo disco dal piolo 0 al piolo sposta i primi n-1 dischi dal piolo 2 al piolo 1 rispettando l’ordine

Descrivere il processo ricorsivo implementato nel seguente programma e l’albero di ricorsione PROGRAM TorreDiHanoi (output); TYPE piolo=0..2; VAR i, nmossa: integer; PROCEDURE muovi(disco:integer; sorgente, destinazione:piolo); BEGIN nmossa:=nmossa+1; writeln(nmossa:3, ' muovi il disco ',disco:2, ' da',sorgente:2, ' a', destinazione:2) END; PROCEDURE Hanoi(n:integer; sorgente, destinazione, ausiliario:piolo); BEGIN IF n=1 THEN muovi(1,sorgente, destinazione) ELSE BEGIN Hanoi(n-1,sorgente, ausiliario, destinazione); muovi(n,sorgente, destinazione); Hanoi(n-1, ausiliario, destinazione,sorgente) END END; BEGIN FOR i:=2 TO 4 DO BEGIN nmossa:=0; writeln(' '); writeln(' mossa per',i:3,' dischi'); Hanoi(i,0,1,2); readln END END.

CONSIGLI PER LA PROGETTAZIONE DI ALGORITMI RICORSIVI 1 – Assicurarsi di aver preso in considerazione tutti i possibili casi base Ad esempio nel caso del Fattoriale non avevamo tenuto conto del caso di N<0 FUNCTION Fattoriale (N:integer):integer; BEGIN IF N=0 THEN Fattoriale:=1 ELSE Fattoriale:=N*Fattoriale(N-1) END;

RICORDARSI CHE l’ordine con cui le istruzioni vengono eseguite, se prima o dopo la chiamata ricorsiva A-se una o più istruzioni riducono la dimensione del problema esse devono precedere la chiamata ricorsiva B-se una o più istruzioni necessitano del risultato della ricorsione vanno poste dopo la chiamata ricorsiva CORREZIONE ESERCIZI

PROGRAM Simmetrica(input,output); { Assegnata una matrice NxN determinare, con una procedura ricorsiva,se è simmetrica.} TYPE Arrayx=Array[1..10,1..10] of integer; VAR A:arrayx; N,M1,M2:integer; FUNCTION simme(VAR A1:arrayx;M,I,J:integer):boolean; BEGIN IF i>M THEN simme:=TRUE ELSE IF A1[i,j]=A1[j,i] THEN BEGIN IF j<=i THEN simme:=simme(A1,M,i,j+1) ELSE simme:=simme(A1,M,i+1,1) END ELSE simme:=FALSE END; {******** MAIN************} N:=5;M1:=2;M2:=1; ScriviMatrice(A,N); writeln; writeln(' La simmetria Š ',simme(A,N,M1,M2)); readln END.

PROGRAM palin(output,input); TYPE Strin=STRING[10]; VAR A1:strin; N1,som1:integer; FUNCTION palindroma(VAR A:strin;N,i:integer):boolean; BEGIN IF i>N DIV 2 THEN palindroma:=TRUE ELSE BEGIN IF A[i]=A[N-i+1] THEN palindroma:=palindroma(A,N,i+1) ELSE palindroma:=FALSE END; ***MAIN*** BEGIN A1:='annna'; N1:=length(A1); writeln(A1,' è ',palindroma(A1,N1,1)); readln END.

*************************** Fornire una funzione ricorsiva tale che assegnata una lista ordinata di numeri interi dica quanti e quali dei numeri in essa contenuti sono numeri di Fibonacci. Es. L1=[1,3,7,11,13, 19, 21, 33, 34] I numeri di Fibonacci presenti nella lista sono 6(1, 3, 13, 21, 34) *************************** Data una matrice di interi MxN scrivere una funzione ricorsiva che valga TRUE se la somma degli elementi di ogni riga è minore della riga precedente e la somma degli elementi di ogni colonna è maggiore della somma della colonna precedente, FALSE altrimenti TRUE FALSE

ESERCIZIO Assegnate due stringhe M1 e M2 verificare se M2 è un prefisso di S1 con una procedura ricorsiva.