1 / 105

CAPITOLO 15

CAPITOLO 15. 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:

daw
Download Presentation

CAPITOLO 15

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CAPITOLO 15

  2. 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) dimostriamo che è vero S(n+1). Esempio Vogliamo dimostrare che S(n): caso base Poniamo n=0 avremo che è quindi dimostrato vero

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

  4. 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.

  5. 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

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

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

  8. 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)); 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;

  9. GCD:=GCD(N, M MOD N) No No No No N=0? N=0? N=0? N=0? N=0? Si GCD GCD GCD GCD GCD 6 GCD(66,48) GCD(48,18) GCD(18,12) GCD(12,6) GCD(6,0) GCD(48,18) GCD(18,12) GCD(12,6) GCD(6,0) Turbo Pascal Version 7.0 Assegna M e N 66 48 **push** GCD(66,48) **push** GCD(48,18) **push** GCD(18,12) **push** GCD(12,6) **pop** N= 0 **pop** N= 6 **pop** N= 12 **pop** N= 18 Il GCD e':= 6 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;

  10. 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 CASE BASE o STOPPING CASE. Nel caso del GCD il CASE BASE è il caso in cui N=0. CASE 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 CASE BASE. Il meccanismo di gestione delle chiamate ricorsive è quello dello stack, si fa cioè ricorso alla tecnica LIFO ed è chiamato Run-time stack.

  11. 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;

  12. No No No Si N=0? N=0? N=0? N=0? PotenzaN 0.9* PotenzaN 0.9* PotenzaN 0.9* PotenzaN(0.9,2) PotenzaN(0.9,1) PotenzaN(0.9,0) PotenzaN 1 PotenzaN(0.9,3) PotenzaN(0.9,3) PotenzaN(0.9,2) PotenzaN(0.9,1) PotenzaN(0.9,0) Turbo Pascal Version 7.0 Assegna Xre e N 0.9 3 **push** 3 **push** 2 **push** 1 **pop** 1 **pop** 2 **pop** 3 0.900 elevato a 3 e'= 0.729 FUNCTION PotenzaN(Xre:real,N:integer):real; BEGIN IF N=0 THEN PotenzaN :=1 ELSE writeln(‘**push** ‘,N); PotenzaN:= Xre*PotenzaN(Xre,N-1); writeln(‘**pop** ‘,N); END;

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

  14. IF i parametri fanno riferimento a un Case 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

  15. 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 sale nello stack e si chiude il processo immediatemente precedente e così via di seguito.

  16. Per scrivere un algoritmo ricorsivo bisogna soddisfare le seguenti condizioni: 1. Esiste almeno un case 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 case base nel corso della elaborazione del problema originale.

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

  18. DIMOSTRAZIONE PER INDUZIONE DELLA CORRETTEZZA DELL’ALGORTIMO RICORSIVO PER IL GCD caso base Poniamo GCD(M,0)=M passo induttivo Dobbiamo ora dimostrare che GCD(M’,N’)=GCD(N, M MOD N) Supponiamo GCD(M’,N’)=X allora M’=hX e N’=zX dove 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+zX inoltre 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)

  19. essendo N’=M MOD N questo implica per definizione che ma N’=zX DIMOSTRAZIONE PER INDUZIONE DELLA CORRETTEZZA DELL’ALGORTIMO RICORSIVO PER IL GCD caso base Poniamo GCD(M,0)=M passo induttivo Dobbiamo ora dimostrare che GCD(M’,N’)=GCD(N, M MOD N) Supponiamo GCD(M’,N’)=X allora M’=hX e N’=zX dove h e z sono interi M=kN+N’ dove k è un intero allora M=kN+zX inoltre 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) q.e.d.

  20. 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 CASE BASE.

  21. 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 gentil farfalletta a volo sorpresa avea tra l’erbetta La Vispa Teresa Pseudo-codice reset(Teresa) InvertiRighe (Teresa)

  22. 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; PROCEDURE MostraRigheInvertite (VAR Teresa:text); BEGIN StoreDisplay(Teresa) END; { BODY } BEGIN reset(Teresa); MostraRigheInvertite END.

  23. 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; PROCEDURE MostraRigheInvertite(VAR FInput:text); BEGIN StoreDisplay(FInput) END; {BODY } BEGIN assign(FInput,'C:\TP\ESEMPI\TERESA.TXT'); reset(FInput); MostraRigheInvertite(FInput); readln END. base case *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

  24. From - Thu Aug 26 07:09:19 1999 Return-Path: <epontell@cs.nmsu.edu> Received: from di.unito.it (pianeta.di.unito.it) by sole.cib.na.cnr.it (4.1/SMI-4.1) id AA29055; Sun, 1 Aug 99 06:10:35 +0200 Received: from cs.CS.NMSU.Edu by di.unito.it (8.9.1a/SMI-INFODIP) id FAA23820; Sun, 1 Aug 1999 05:50:02 +0200 (MET DST) Received: from cs.nmsu.edu (epontell@pippo [128.123.64.31]) by cs.CS.NMSU.Edu (8.8.6/8.8.6) with ESMTP id VAA27225; Sat, 31 Jul 1999 21:53:44 -0600 (MDT) Sender: epontell@cs.nmsu.edu Message-Id: <37A3C4CA.7A997A9A@cs.nmsu.edu> Date: Sat, 31 Jul 1999 21:53:46 -0600 From: Enrico <epontell@cs.nmsu.edu> Organization: Laboratory for Logic & Databases X-Mailer: Mozilla 4.05 [en] (X11; I; Linux 2.0.32 i686) Mime-Version: 1.0 To: aiia@di.unito.it, ccl@ps.uni-sb.de, compulog@doc.imperial.ac.uk, compulognet-parimp@clip.dia.fi.upm.es, elsnet-list@let.ruu.nl, gulp@di.unipi.it, lpnmr@cs.engr.uky.edu, lprolog@central.cis.upenn.edu, clp@iscs.nus.edu.sg, lp-internet@doc.ic.ac.uk, concurrency@cwi.nl, dappia@di.fct.unl.pt Subject: Research Assistantships at NMSU Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-UIDL: b0fa9065af5ad288d1475b519b3ad95b Status: U X-Mozilla-Status: 0001 Applications are invited for several Research Assistant Positions in the Laboratory for Logic and Databases of the Dept. of Computer Science at New Mexico State University.

  25. From - Thu Aug 26 07:09:19 1999 Return-Path: <epontell@cs.nmsu.edu> ............ ............ ............ ............ X-Mozilla-Status: messaggio From - Thu Aug 28 09:09:29 1999 Return-Path: <ernb@sole.cib.na.cnr.it> ............ ............ ............ ............ X-Mozilla-Status: messaggio

  26. ElaboraTesto(Rigo) Pseudo codice IF Not eof(InFile) THEN readln(Finput,Rigo) ElaboraTesto(Rigo)

  27. FATTORIALE 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 cba bca - 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 cba bca

  28. 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;

  29. Sommatoria dei primi N interi positivi 1. La somma dei primi 0 interi positivi vale 0. 2. La somma dei primi N interi positivi è uguale alla somma dei primi N-1 interi più N. FUNCTION Sommatoria (N:integer):integer; BEGIN IF N=0 THEN Sommatoria:=1 ELSE Sommatoria :=N+Sommatoria(N-1) END;

  30. 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 Somma  0 ELSE ShowSums(N-1, M, Sum) Somma  Somma+N IF N MOD M=0 THEN scrivi N e Somma

  31. PROGRAM SommaRicorsiva(inputoutput); VAR Nin,Min,Sumout:integer; PROCEDURE ShowSums(N,M:integer; VAR Sum:integer); VAR Temp:integer; BEGIN IF N=0 THEN BEGIN writeln(' Somme parziali '); 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.

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

  33. Esempio con due CASE BASE Problema: Assegnare agli elementi dell’Array di interi Ints, dei numeri compresi nell’intervallo 1..TotalAssigned. 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 CASE 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

  34. TotalAssigned = 0 Temp< = 0 TotalAssigned = TotalAssigned + 1 Ints[TotalAssigned ]  Temp Pseudo-Codice {Indichiamo con Left quanti numeri positivi è ancora possibile assegnare e con Temp il valore letto } IF Left = 0 THEN gestisci il CASE BASE N°1 ELSE read(Temp) IF Temp<=0 THEN gestisci il CASE BASE N°2 ELSE istruzioni prima della ricorsione FillIn(Left-1,TotalAssigned,Ints) istruzioni dopo la ricorsione

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

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

  37. Alcuni suggerimenti • Fatti importanti • come si passano i valori di variabili • 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 PROCEDUREFillIn(Left:integer; VAR TotalAssigned:integer; VAR Ints:IntsArray); VAR Temp: integer;

  38. BEGIN read(Temp); IF Temp <=0 THEN BEGIN writeln('E'' stato introdotto un numero negativo. '); TotalAssigned:=0; END ELSE BEGIN FillIn(Left-1, TotalAssigned,Ints); TotalAssigned:= TotalAssigned+1; Ints[TotalAssigned]:=Temp END END ElaboraTesto(Rigo) Pseudo codice IF Not eof(InFile) THEN readln(Finput,Rigo) ElaboraTesto(Rigo) • 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 b- poste dopo la chiamata ricorsiva

  39. PROCEDURE FillIn(Left:integer; VAR TotalAssigned:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left=0 THEN BEGIN writeln('Non mettere altri valori. '); TotalAssigned:=0; END ELSE BEGIN read(Temp); IF Temp <=0 THEN BEGIN writeln('E'' stato introdotto un negativo. '); TotalAssigned:=0; END ELSE BEGIN FillIn(Left-1, TotalAssigned,Ints); TotalAssigned:= TotalAssigned+1; Ints[TotalAssigned]:=Temp END END END; PROCEDURE FillIn2(Left:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left<>0 THEN BEGIN FillIn(Left-1,Ints); read(Temp); Ints[Left]:=Temp END END END; FillIn2 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 10 20 30 40 50 FillIn3 push** 5 10 push** 4 20 push** 3 30 push** 2 40 push** 1 50 pop** 1 pop** 2 pop** 3 pop** 4 ARRAY 50 40 30 20 10 FillIn1 10 push** 5 20 push** 4 30 push** 3 40 push** 2 50 push** 1 pop** 1 pop** 2 pop** 3 pop** 4 pop** 5 ARRAY 50 40 30 20 10 PROCEDURE FillIn3(Left:integer; VAR Ints:IntsArray); VAR Temp: integer; BEGIN IF Left<>0 THEN BEGIN read(Temp); FillIn(Left-1,Ints); Ints[Left]:=Temp END END;

  40. FillIn1 10 push** 5 20 push** 4 30 push** 3 40 push** 2 50 push** 1 pop** 1 pop** 2 pop** 3 pop** 4 pop** 5 ARRAY 50 40 30 20 10 FillIn2 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 10 20 30 40 50 FillIn3 push** 5 10 push** 4 20 push** 3 30 push** 2 40 push** 1 50 pop** 1 pop** 2 pop** 3 pop** 4 ARRAY 50 40 30 20 10

  41. Ricorsione lineare = al massimo una chiamata ricorsiva per blocco 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.

  42. MAIN MAIN PROCEDURE A PROCEDURE B PROCEDURE C(1) PROCEDURE C(1) PROCEDURE C(0) PROCEDURE C(0) Esempio PROGRAM TreeExample(output); PROCEDURE C(N:integer); BEGIN IF N>0 THEN C(N-1) END; PROCEDURE B; BEGIN C(1) END; PROCEDURE A; BEGIN B END; {BODY} BEGIN A; C(1); writeln(‘Fine’) END. • Esecuzione • 1 main chiama A ; • 2 A chiama B; • 3 B chiama C(1); • 4 C(1) chiama C(0); • 5 C(0) ritorna C(1); • 6 C(1) ritorna B; • 7 B ritorna A; • 8 A ritorna al main; • 9 main chiama C(1); • 10 C(1) chiama C(0); • 11 C(0) ritorna C(1); • 12 C(1) ritorna main; • 13 main chiama writeln(‘Fine’) • 14 writeln(‘Fine’)

  43. 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. 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

  44. main chiama Fine main writeln main chiama A Fine ritorna a main main chiama C(1) A A chiama B A ritorna a main C(1) ritorna a main B B ritorna A B chiama C(1) C(1) C(1) C(1) ritorna a B C(1) chiama C(0) C(1) chiama C(0) C(0) ritorna a C(1) C(0) C(0) ritorna a C(1) C(0)

  45. main writeln A B C(1) C(1) C(0) C(0)

  46. 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.

  47. NullString {ritorna una la stringa nulla ''.} ConvertSysString {converte una stringa rappresentata in un qualche sistema nella stringa equivalente di type StringADT} ReadCh {legge i caratteri di una stringa da un file e se supera la lunghezza prefissata o trova eoln restituisce un carattere sentinella} ReadString {legge la stringa da un file escludendo eventuali caratteri sentinella} ReadlnString {legge una stringa da una linea di un file predeterminato} Ach {ritorna il carattere N-esimo di una stringa } StrLength {ritorna la lunghezza della stringa} WriteString {scrive una stringa in un file} WritelnString {scrive una stringa in un file seguita da un <eoln>} LowerCase {trasforma le maiuscole in minuscole} StrEqual {ritorna TRUE se due stringhe hanno gli stessi caratteri e la stessa lunghezza} StrExtract {copia una stringa di una predeterminata lunghezza a partire da una determinata posizione in una stringa di output} StartPos {Ritorna la posizione di partenza di una data sub-stringa nell'ambito di una preassegnata stringa} StrLessThan {ritorna TRUE se la prima stringa precede alfabeticamente la seconda} ChConcat {concatena un singolo carattere ad una stringa} StrConcat {concatena due stringhe} StrRemove {rimuove un predeterminato numero di caratteri a partire da una certa posizione di una stringa di input/output} StrInsert {inserisce un predeterminata stringa di caratteri a partire da una certa posizione in una variabile stringa.} ScriviSTringa {scrivi la stringa} OPERATORI SULLE STRINGHE

  48. UNIT Stringa; INTERFACE CONST MaxLength=80; TYPE SysString=STRING[MaxLength]; StringADT=RECORD Chars:ARRAY[1.. MaxLength] OF char; Len:0.. MaxLength END;

  49. FUNCTION StartPos(Substr, SearchStr:StringADT):integer; {Ritorna la posizione di partenza di una data sub-stringa Substr nell'ambito di una preassegnata SearchStr stringa} VAR SLen, {numero di caratteri della sub-stringa} Pos: integer; {posizione di partenza della sub-stringa} Found: Boolean; CandStr: StringADT; {sub-stringa candidata } BEGIN SLen:=SubStr.Len; Found:=FALSE; Pos:=1; WHILE NOT (SearchStr.Len+1-Pos>SLen) AND NOT Found DO BEGIN StrExtract(SearchStr,Pos,SLen,CandStr); IF StrEqual(CandStr,SearchStr) THEN Found:=TRUE ELSE Pos:=Pos+1 END; IF Found THEN StratPos:=Pos ELSE StratPos:=0 END; StringADT=RECORD Chars:ARRAY[1.. MaxLength] OF char; Len:0.. MaxLength END;

  50. PROCEDURE StrExtract(InStr:StringADT; Start, TotalChs:integer; VAR OutStr: StringADT); {copia da una stringa di input InStr una stringa di una predeterminata lunghezza TotalChs a partire da una determinata posizione Start in una stringa di output OutStr} VAR InStrPos, {Posizione di un carattere nella stringa di input} OutStrPos:integer; {Posizione di un carattere nella stringa di output} BEGIN WITH OutStr DO BEGIN IF Start > InStr.Len THEN {controlla che il punto di partenza non sia fuori stringa} Len:=0 ELSE IF TotalChs > InStr.Len+1-Start THEN Len:=InStr.Len+1-Start ELSE Len:=TotalChs; InStrPos:=Start; FOR OutStrPos:=1 TO Len DO BEGIN Chars[OutStrPos]:=InStr.Chars[InStrPos]; InStrPos:=InStrPos+1 END END END; StringADT=RECORD Chars:ARRAY[1.. MaxLength] OF char; Len:0.. MaxLength END;

More Related