[successivo]
[precedente]
[inizio]
[fine]
[indice generale]
[indice ridotto]
[translators]
[docinfo]
[indice analitico]
[volume]
[parte]
Capitolo 477. Una tecnica per simulare la ricorsione in COBOL
Questo capitolo contiene la ricostruzione di un documento con lo stesso nome, dello stesso autore, concluso nel mese di giugno del 1985, dopo un periodo di studio sul linguaggio COBOL. Il COBOL è un linguaggio procedurale che offre esclusivamente la gestione di variabili globali, pertanto non consente di realizzare la ricorsione; tuttavia, in questo capitolo, come esercizio, si descrive una tecnica per arrivare a ottenere un risultato simile alla ricorsione comune.
Nel capitolo si fa riferimento a tre algoritmi noti: torre di Hanoi, quicksort e permutazioni. Questi algoritmi sono descritti nel capitolo 421.
Alla fine del capitolo è riportata la bibliografia dello studio originale. Tutti gli esempi originali con il linguaggio MPL II sono stati omessi, anche se nella bibliografia questo linguaggio viene citato.
477.1
Il concetto di locale e di globale
Niklaus Wirth [1] spiega molto bene la differenza tra il concetto di locale e di globale all'interno di un programma:
Se un oggetto –una costante, una variabile, una procedura, una funzione o un tipo– è significativo solo all'interno di una parte determinata del programma, viene chiamato «locale». Spesso conviene rappresentare questa parte mediante una procedura; gli oggetti locali vengono allora indicati nel titolo della procedura. Dato che le procedure stesse possono essere locali, può accadere che più indicazioni di procedura siano innestate l'una nell'altra.
Nell'ambito della procedura si possono quindi riconoscere due tipi di oggetti: gli oggetti «locali» e gli oggetti «non locali». Questi ultimi sono oggetti definiti nel programma (o nella procedura) in cui è inserita la procedura («ambiente» della procedura). Se sono definiti nel programma principale, sono detti «globali». In una procedura il campo di influenza degli oggetti locali corrisponde al corpo della procedura. In particolare, terminata l'esecuzione della procedura, le variabili locali saranno ancora disponibili per indicare dei nuovi valori; chiaramente, in una chiamata successiva della stessa procedura, i valori delle variabili locali saranno diversi da quelli della chiamata precedente.
È essenziale che i nomi degli oggetti locali non debbano dipendere dall'ambiente della procedura. Ma, in tal modo, può accadere che un nome «x», scelto per un oggetto locale della procedura «P», sia identico a quello di un oggetto definito nel programma ambiente di «P». Questa situazione però è corretta solo se la grandezza non locale «x» non è significativa per «P», cioè non viene applicata in «P». Si adotta quindi la «regola fondamentale» che «x» denoti entro «P» la grandezza locale e fuori da «P» quella non locale.
477.2
La ricorsione
«La ricorsione», come spiegano Ledgard, Nagin e Hueras [2], «è un metodo di definizione in cui l'oggetto della definizione è usato all'interno della definizione». Per esempio si può considerare la seguente definizione della parola «discendente»:
Un discendente di una persona è il figlio o la figlia di quella persona, o un discendente del figlio o della figlia.
Quindi, come scrive Lawrie Moore [3], un sottoprogramma ricorsivo «è un sottoprogramma che corrisponde direttamente e utilizza una definizione ricorsiva». Ovvero, molto più semplicemente come dicono Aho, Hopcroft e Ullman 4: «Una procedura che chiama se stessa, direttamente o indirettamente, si dice essere ricorsiva».
Moore [3] inoltre aggiunge quanto segue: «La chiamata genera un nuovo blocco di programma, con il suo proprio ambito, il suo proprio spazio di lavoro, la sua propria esistenza virtuale. [...] Questo processo prende luogo al momento dell'esecuzione del programma (run-time). Al momento della compilazione né la macchina, né l'intelligenza umana possono dire quante volte la procedura sarà richiamata al momento dell'esecuzione. Perciò, la creazione di un nuovo blocco di programma al momento dell'esecuzione è un processo dinamico. La creazione ricorsiva di nuovi blocchi di programma è una struttura di programmazione dinamica».
477.3
Proprietà del linguaggio ricorsivo
La definizione di procedura ricorsiva data da Aho, Hopcroft e Ullman è una condizione necessaria ma non sufficiente perché un linguaggio di programmazione possa definirsi ricorsivo. Infatti, è tale quel linguaggio che oltre a permettere la chiamata di una procedura da parte di se stessa, permette una dichiarazione locale delle variabili, ovvero permette l'allocazione dinamica delle variabili stesse.
Non vi è dubbio che il linguaggio COBOL non sia ricorsivo, eppure ammette che all'interno di un paragrafo si faccia la chiamata dello stesso paragrafo tramite l'istruzione PERFORM. In effetti non si parla di ricorsione proprio perché il COBOL gestisce solo variabili globali.
477.4
Descrizione della tecnica per simulare la ricorsione in COBOL
Le variabili di scambio di un sottoprogramma possono collegarsi all'esterno, a seconda del contesto del programma, in tre modi: in input, in output o in input-output, a seconda che importi che i dati entrino nel sottoprogramma ma non escano, che i dati escano soltanto oppure che i dati debbano prima entrare e poi uscire modificati.
La pseudocodifica utilizzata per mostrare gli esempi, prima di presentare la trasformazione in COBOL, si rifà al linguaggio MPL II Burroughs, dove le variabili di scambio di una procedura vengono semplicemente nominate a fianco del nome della procedura tra parentesi. Ciò corrisponde a una dichiarazione implicita di quelle variabili con ambito locale e con caratteristiche identiche a quelle usate nelle chiamate relative. In particolare, se nella chiamata vengono usate costanti alfanumeriche, la variabile corrispondente sarà di tipo alfanumerico di lunghezza pari alla costante trasmittente, se di tipo numerico, la variabile corrispondente sarà di tipo numerico opportuno: intero o a virgola mobile.
Quindi, in questo tipo di pseudocodifica non sono permesse le variabili di scambio in output.
Le variabili di scambio di questa pseudocodifica si collegano per posizione.
Il problema della simulazione della ricorsione si risolve utilizzando una pila (stack) per ogni variabile locale.
La tecnica è indicata molto semplicemente da Jerrold L. Wagener [5]. Una volta determinato a priori qual è il numero massimo di livelli della ricorsione, occorre associare a ogni variabile locale, che non sia collegata con l'esterno in input-output, una pila con dimensioni pari a quel numero. Quindi, a una variabile scalare viene associato un vettore, a un vettore viene associata una matrice a due dimensioni e così di seguito. L'indice della pila (stack pointer) viene indicato con SP.
La simulazione si divide in due fasi: la prima deve essere effettuata subito prima della chiamata ricorsiva e consiste nella conservazione delle varie pile dei valori delle variabili di scambio che non sono in input-output con un'operazione di inserimento (push); la seconda deve essere effettuata subito dopo la chiamata ricorsiva e consiste nel recupero dalle varie pile dei valori originali delle variabili con un'operazione di estrazione (pop).
Figura 477.1. Confronto tra una procedura ricorsiva e la sua trasformazione non ricorsiva, attraverso la pseudocodifica.
# #
# Procedura ricorsiva # Trasformazione non ricorsiva
# #
PROC1 (V, G, Z) PROC1
. .
. .
. .
. # push
. SP := SP + 1
. SAVEV(SP) := V
. SAVEZ(SP) := Z
# G è una variabile in # chiamata
# input-output Z := Z -1
PROC1 (V, G, Z-1) PROC1
. # pop
. V := SAVEV(SP)
. Z := SAVEZ(SP)
. SP := SP - 1
. .
. .
. .
END PROC1 END PROC1
|
È bene precisare che la tecnica è valida solo se all'interno di una procedura ricorsiva tutte le iterazioni che contengono una chiamata (diretta o indiretta) alla stessa procedura sono a loro volta espresse in forma ricorsiva (si veda il problema delle permutazioni).
477.5
Torre di Hanoi
Segue la descrizione dell'algoritmo attraverso la pseudocodifica in forma ricorsiva. Nella sezione 421.4.3 viene descritto il problema della torre di Hanoi.
Variabile | Descrizione |
N
| È la dimensione della torre espressa in numero di anelli: gli anelli sono numerati da 1 a N. |
P1
| È il numero del piolo su cui si trova inizialmente la pila di N anelli. |
P2
| È il numero del piolo su cui deve essere spostata la pila di anelli. |
6-P1-P2
| È il numero dell'altro piolo. Funziona così se i pioli sono numerati da 1 a 3. |
|
HANOI (N, P1, P2)
IF N > 0
THEN
HANOI (N-1, P1, 6-P1-P2)
scrivi: "Muovi l'anello" N "dal piolo" P1 "al piolo" P2
HANOI (N-1, 6-P1-P2, P2)
END IF
END HANOI
|
|
Segue la descrizione della trasformazione in modo tale da simulare la ricorsione.
Variabile | Descrizione |
SAVEN
| È il vettore utilizzato per conservare il valore di N. |
SAVEP1
| È il vettore utilizzato per conservare il valore di P1. |
SAVEP2
| È il vettore utilizzato per conservare il valore di P2. |
SP
| È l'indice dei vettori usati per salvare i valori (stack pointer). |
|
HANOI (N, P1, P2)
IF N > 0
THEN
SP := SP + 1
SAVEN(SP) := N
SAVEP2(SP) := P2
N := N - 1
P2 := 6 - P1 - P2
HANOI
N := SAVEN(SP)
P2 := SAVEP2(SP)
SP = SP - 1
scrivi: "Muovi l'anello" N "dal piolo" P1 "al piolo" P2
SP := SP + 1
SAVEN(SP) := N
SAVEP1(SP) := P1
N := N - 1
P1 := 6 - P1 - P2
HANOI
N := SAVEN(SP)
P1 := SAVEP1(SP)
SP = SP - 1
END IF
END HANOI
|
|
Listato 477.6. Soluzione in COBOL del problema della torre di Hanoi, con la simulazione della ricorsione.
000600 IDENTIFICATION DIVISION.
000700 PROGRAM-ID. HC04.
000800 AUTHOR. DANIELE GIACOMINI.
000900 DATE-WRITTEN. 1984-08-18.
001000
001100
001200 ENVIRONMENT DIVISION.
001300
001400
001500 DATA DIVISION.
001600
001700
001800 WORKING-STORAGE SECTION.
001900
002000 01 RECORD-STACKS.
002100 02 SAVEN OCCURS 100 TIMES PIC 99.
002200 02 SAVEP1 OCCURS 100 TIMES PIC 9.
002300 02 SAVEP2 OCCURS 100 TIMES PIC 9.
002400
002500 01 STACK-POINTER.
002600 02 SP PIC 99 VALUE 0.
002700
002800 01 VARIABILI-SCALARI.
002900 02 N PIC 99.
003000 02 P1 PIC 9.
003100 02 P2 PIC 9.
003200
003300
003400 PROCEDURE DIVISION.
003500
003600 MAIN.
003700
003800 DISPLAY "INSERISCI LA DIMENSIONE DELLA TORRE".
003900 DISPLAY "(DUE CARATTERI)".
004000 ACCEPT N.
004100
004200 DISPLAY "INSERISCI LA POSIZIONE INIZIALE DELLA TORRE".
004300 DISPLAY "(UN CARATTERE)".
004400 ACCEPT P1.
004500
004600 DISPLAY "INSERISCI LA DESTINAZIONE DELLA TORRE".
004700 DISPLAY "(UN CARATTERE)".
004800 ACCEPT P2.
004900
005000 PERFORM HANOI.
005100
005200 STOP RUN.
005300
005400 HANOI.
005500
005600 IF N > 0
005700 THEN
005800*
005900* push per conservare le variabili di scambio
006000*
006100 COMPUTE SP = SP + 1,
006200 COMPUTE SAVEN(SP) = N,
006300 COMPUTE SAVEP2(SP) = P2,
006400*
006500* cambiamenti alle variabili di scambio prima della
006600* chiamata
006700*
006800 COMPUTE N = N - 1,
006900 COMPUTE P2 = 6 - P1 - P2,
007000*
007100* chiamata della procedura
007200*
007300 PERFORM HANOI,
007400*
007500* pop per recuperare i valori delle variabili di scambio
007600*
007700 COMPUTE P2 = SAVEP2(SP),
007800 COMPUTE N = SAVEN(SP),
007900 COMPUTE SP = SP - 1,
008000
008100 DISPLAY "MUOVI L'ANELLO ", N, " DAL PIOLO ", P1,
008200 " AL PIOLO ", P2,
008300
008400*
008500* push per conservare le variabili di scambio
008600*
008700 COMPUTE SP = SP + 1,
008800 COMPUTE SAVEN(SP) = N,
008900 COMPUTE SAVEP1(SP) = P1,
009000*
009100* modifica dei valori delle variabili di scambio
009200*
009300 COMPUTE N = N - 1,
009400 COMPUTE P1 = 6 - P1 - P2,
009500*
009600* chiamata della procedura
009700*
009800 PERFORM HANOI,
009900*
010000* pop per recuperare i valori delle variabili di scambio
010100*
010200 COMPUTE P1 = SAVEP1(SP),
010300 COMPUTE N = SAVEN(SP),
010400 COMPUTE SP = SP - 1.
010500
|
|
477.6
Quicksort (ordinamento non decrescente)
Segue la descrizione dell'algoritmo attraverso la pseudocodifica in forma ricorsiva; si ricorda che l'algoritmo del Quicksort si risolve con due subroutine: una serve a suddividere il vettore; l'altra esegue le chiamate ricorsive. Nella sezione 421.4.4 viene descritto il problema del Quicksort in modo dettagliato.
Variabile | Descrizione |
LISTA
| L'array da ordinare in modo crescente. |
A
| L'indice inferiore del segmento di array da ordinare. |
Z
| L'indice superiore del segmento di array da ordinare. |
CF
| Sta per «collocazione finale» ed è l'indice che cerca e trova la posizione giusta di un elemento nell'array. |
I
| È l'indice che insieme a CF serve a ripartire l'array. |
|
PART (LISTA, A, Z)
LOCAL I INTEGER
LOCAL CF INTEGER
# si assume che A < U
I := A + 1
CF := Z
WHILE TRUE # ciclo senza fine.
WHILE TRUE
# sposta I a destra
IF (LISTA[I] > LISTA[A]) OR I >= CF
THEN
BREAK
ELSE
I := I + 1
END IF
END WHILE
WHILE TRUE
# sposta CF a sinistra
IF (LISTA[CF] <= LISTA[A])
THEN
BREAK
ELSE
CF := CF - 1
END IF
END WHILE
IF CF <= I
THEN
# è avvenuto l'incontro tra I e CF
BREAK
ELSE
# vengono scambiati i valori
LISTA[CF] :==: LISTA[I]
I := I + 1
CF := CF - 1
END IF
END WHILE
# a questo punto LISTA[A:Z] è stata ripartita e CF è la collocazione
# di LISTA[A]
LISTA[CF] :==: LISTA[A]
# a questo punto, LISTA[CF] è un elemento (un valore) nella giusta
# posizione
RETURN CF
END PART
|
|
QSORT (LISTA, A, Z)
LOCAL CF INTEGER
IF Z > A
THEN
CF := PART (@LISTA, A, Z)
QSORT (@LISTA, A, CF-1)
QSORT (@LISTA, CF+1, Z)
END IF
END QSORT
|
|
Vale la pena di osservare che l'array viene indicato nelle chiamate in modo che alla subroutine sia inviato un riferimento a quello originale, perché le variazioni fatte all'interno delle subroutine devono riflettersi sull'array originale.
|
La subroutine QSORT è quella che richiede la trasformazione per la simulazione della ricorsione; tuttavia, anche la subroutine deve essere adattata in modo tale da gestire la variabile CF come variabile globale (non potendo gestire variabili di output). Segue la descrizione di tali adattamenti.
Variabile | Descrizione |
SAVEA
| È il vettore utilizzato per conservare il valore di A. |
SAVEZ
| È il vettore utilizzato per conservare il valore di Z. |
SP
| È l'indice dei vettori usati per salvare i valori (stack pointer). |
|
PART (LISTA, A, Z)
LOCAL I INTEGER
# si assume che A < U
I := A + 1
CF := Z
WHILE TRUE # ciclo senza fine.
WHILE TRUE
# sposta I a destra
IF (LISTA[I] > LISTA[A]) OR I >= CF
THEN
BREAK
ELSE
I := I + 1
END IF
END WHILE
WHILE TRUE
# sposta CF a sinistra
IF (LISTA[CF] <= LISTA[A])
THEN
BREAK
ELSE
CF := CF - 1
END IF
END WHILE
IF CF <= I
THEN
# è avvenuto l'incontro tra I e CF
BREAK
ELSE
# vengono scambiati i valori
LISTA[CF] :==: LISTA[I]
I := I + 1
CF := CF - 1
END IF
END WHILE
# a questo punto LISTA[A:Z] è stata ripartita e CF è la collocazione
# di LISTA[A]
LISTA[CF] :==: LISTA[A]
# a questo punto, LISTA[CF] è un elemento (un valore) nella giusta
# posizione
END PART
|
|
QSORT
IF Z > A
THEN
PART
SP := SP + 1
SAVEZ(SP) := Z
Z := CF - 1
QSORT
# SP := SP - 1
# SP := SP + 1
SAVEA(SP) := A
A := CF + 1
QSORT
A := SAVEA(SP)
SP := SP - 1
END IF
END QSORT
|
|
Listato 477.13. Soluzione in COBOL del problema del Quicksort, con la simulazione della ricorsione. Si osservi che CF è una parola riservata del linguaggio, pertanto viene sostituita con C-F.
000600 IDENTIFICATION DIVISION.
000700 PROGRAM-ID. HC06.
000800 AUTHOR. DANIELE GIACOMINI.
000900 DATE-WRITTEN. 1984-08-22.
001000
001100
001200 ENVIRONMENT DIVISION.
001300
001400
001500 DATA DIVISION.
001600
001700
001800 WORKING-STORAGE SECTION.
001900
002000 01 RECORD-STACKS.
002100 02 SAVEA OCCURS 100 TIMES PIC 999.
002200 02 SAVEZ OCCURS 100 TIMES PIC 999.
002300
002400 01 STACK-POINTER.
002500 02 SP PIC 999.
002600
002700 01 VARIABILI-SCALARI.
002800 02 C-F PIC 999.
002900 02 A PIC 999.
003000 02 Z PIC 999.
003100 02 TEMP PIC X(15).
003200 02 I PIC 999.
003300 02 J PIC 999.
003400
003500 01 RECORD-TABELLA.
003600 02 TABELLA OCCURS 100 TIMES PIC X(15).
003700
003800 PROCEDURE DIVISION.
003900
004000 MAIN.
004100
004200 DISPLAY "INSERISCI IL NUMERO DI ELEMENTI DA ORDINARE".
004300 DISPLAY "(TRE CIFRE)".
004400 ACCEPT Z.
004500 IF Z > 100
004600 THEN
004700 STOP RUN.
004800
004900 COMPUTE A = 1.
005000
005100 PERFORM INSERIMENTO-ELEMENTI VARYING J FROM 1 BY 1
005200 UNTIL J > Z.
005300
005400 PERFORM QSORT.
005500
005600 PERFORM OUTPUT-DATI VARYING J FROM 1 BY 1
005700 UNTIL J > Z.
005800
005900 STOP RUN.
006000
006100
006200 INSERIMENTO-ELEMENTI.
006300
006400 DISPLAY "INSERISCI L'ELEMENTO ", J, " DELLA TABELLA".
006500 ACCEPT TABELLA(J).
006600
006700
006800 PART.
006900
007000*
007100* si assume che A < Z
007200*
007300 COMPUTE I = A + 1.
007400 COMPUTE C-F = Z.
007500
007600 PERFORM PART-TESTA-MAINLOOP.
007700 PERFORM PART-MAINLOOP UNTIL C-F < I
007800 OR C-F = I.
007900
008000 MOVE TABELLA(C-F) TO TEMP.
008100 MOVE TABELLA(A) TO TABELLA(C-F).
008200 MOVE TEMP TO TABELLA(A).
008300
008400
008500 PART-TESTA-MAINLOOP.
008600
008700 PERFORM SPOSTA-I-A-DESTRA UNTIL TABELLA(I) > TABELLA(A)
008800 OR I > C-F
008900 OR I = C-F.
009000
009100 PERFORM SPOSTA-C-F-A-SINISTRA
009200 UNTIL TABELLA(C-F) < TABELLA(A)
009300 OR TABELLA(C-F) = TABELLA(A).
009400
009500
009600 PART-MAINLOOP.
009700
009800 MOVE TABELLA(C-F) TO TEMP.
009900 MOVE TABELLA(I) TO TABELLA(C-F).
010000 MOVE TEMP TO TABELLA(I).
010100
010200 COMPUTE I = I + 1.
010300 COMPUTE C-F = C-F - 1.
010400
010500 PERFORM SPOSTA-I-A-DESTRA UNTIL TABELLA(I) > TABELLA(A)
010600 OR I > C-F
010700 OR I = C-F.
010800
010900 PERFORM SPOSTA-C-F-A-SINISTRA
011000 UNTIL TABELLA(C-F) < TABELLA(A)
011100 OR TABELLA(C-F) = TABELLA(A).
011200
011300
011400 SPOSTA-I-A-DESTRA.
011500
011600 COMPUTE I = I + 1.
011700
011800
011900 SPOSTA-C-F-A-SINISTRA.
012000
012100 COMPUTE C-F = C-F - 1.
012200
012300
012400 QSORT.
012500
012600 IF Z > A
012700 THEN
012800*
012900* le variabili che riguardano PART sono tutte in I-O
013000*
013100 PERFORM PART,
013200*
013300* push
013400*
013500 COMPUTE SP = SP + 1,
013600 COMPUTE SAVEZ(SP) = Z,
013700*
013800* cambiamenti alle variabili di scambio
013900*
014000 COMPUTE Z = C-F - 1,
014100*
014200* chiamata
014300*
014400 PERFORM QSORT,
014500*
014600* pop
014700*
014800 COMPUTE Z = SAVEZ(SP),
014900 COMPUTE SP = SP - 1,
015000*
015100* push
015200*
015300 COMPUTE SP = SP + 1,
015400 COMPUTE SAVEA(SP) = A,
015500*
015600* cambiamenti alle variabili di scambio
015700*
015800 COMPUTE A = C-F + 1,
015900*
016000* chiamata
016100*
016200 PERFORM QSORT,
016300*
016400* pop
016500*
016600 COMPUTE A = SAVEA(SP),
016700 COMPUTE SP = SP - 1.
016800
016900
017000 OUTPUT-DATI.
017100
017200 DISPLAY "TABELLA(", J, ") = ", TABELLA(J).
017300
|
|
477.7
Permutazioni
La permutazione degli elementi di un vettore si risolve generalmente attraverso un algoritmo iterativo normale; segue la descrizione dell'algoritmo iterativo in forma di pseudocodifica. Nella sezione 421.4.5 viene descritto il problema delle permutazioni in modo dettagliato.
Variabile | Descrizione |
LISTA
| L'array da permutare. |
A
| L'indice inferiore del segmento di array da permutare. |
Z
| L'indice superiore del segmento di array da permutare. |
K
| È l'indice che serve a scambiare gli elementi. |
|
PERMUTA (LISTA, A, Z)
LOCAL K INTEGER
LOCAL N INTEGER
IF (Z - A) >= 1
# Ci sono almeno due elementi nel segmento di array.
THEN
FOR K := Z; K >= A; K--
LISTA[K] :==: LISTA[Z]
PERMUTA (LISTA, A, Z-1)
LISTA[K] :==: LISTA[Z]
END FOR
ELSE
scrivi LISTA
END IF
END PERMUTA
|
|
Per esercizio, l'algoritmo iterativo viene trasformato in modo ricorsivo:
PERMUTA (LISTA, A, Z)
LOCAL K INTEGER
LOCAL N INTEGER
SCAMBIO_CHIAMATA_SCAMBIO (LISTA, A, Z, K)
IF K >= A
THEN
LISTA[K] :==: LISTA[Z]
PERMUTA (LISTA, A, Z-1)
LISTA[K] :==: LISTA[Z]
SCAMBIO_CHIAMATA_SCAMBIO (LISTA, A, Z, K - 1)
END IF
END SCAMBIO_CHIAMATA_SCAMBIO
IF Z > A
THEN
SCAMBIO_CHIAMATA_SCAMBIO (LISTA, A, Z, Z)
ELSE
scrivi LISTA
END IF
END PERMUTA
|
|
Segue l'adattamento della pseudocodifica appena mostrata, in modo da simulare la ricorsione, utilizzando variabili globali:
Variabile | Descrizione |
SAVEZ
| È il vettore utilizzato per conservare il valore di Z. |
SAVEK
| È il vettore utilizzato per conservare il valore di K. |
SP
| È l'indice dei vettori usati per salvare i valori (stack pointer). |
|
PERMUTA (LISTA, A, Z)
SCAMBIO_CHIAMATA_SCAMBIO
IF K >= A
THEN
LISTA[K] :==: LISTA[Z]
SP := SP + 1
SAVEZ(SP) := Z
Z := Z - 1
PERMUTA
Z := SAVEZ(SP)
SP := SP - 1
LISTA[K] :==: LISTA[Z]
SP := SP + 1
SAVEK(SP) := K
K := K - 1
SCAMBIO_CHIAMATA_SCAMBIO
K := SAVEK(SP)
SP := SP - 1
END IF
END SCAMBIO_CHIAMATA_SCAMBIO
IF Z > A
THEN
SP := SP + 1
SAVEK(SP) := K
K := N
SCAMBIO_CHIAMATA_SCAMBIO
K := SAVEK(SP)
SP := SP - 1
ELSE
scrivi LISTA
END IF
END PERMUTA
|
|
Listato 477.19. Soluzione in COBOL del problema delle permutazioni, con la simulazione della ricorsione.
000600 IDENTIFICATION DIVISION.
000700 PROGRAM-ID. HC07.
000800 AUTHOR. DANIELE GIACOMINI.
000900 DATE-WRITTEN. 1985-06-19.
001000
001100
001200 ENVIRONMENT DIVISION.
001300
001400
001500 DATA DIVISION.
001600
001700
001800 WORKING-STORAGE SECTION.
001900
002000 01 RECORD-STACKS.
002100 02 SAVEZ OCCURS 100 TIMES PIC 9.
002200 02 SAVEK OCCURS 100 TIMES PIC 9.
002300
002400 01 STACK-POINTER.
002500 02 SP PIC 999.
002600
002700 01 VARIABILI-SCALARI.
002800 02 A PIC 9 VALUE 1.
002900 02 Z PIC 9.
003000 02 K PIC 9.
003100 02 TEMP PIC 9.
003200 02 J PIC 99.
003300
003400 01 RECORD-LISTA.
003500 02 LISTA OCCURS 10 TIMES PIC 9.
003600
003700
003800 PROCEDURE DIVISION.
003900
004000 MAIN.
004100
004200 DISPLAY "INSERISCI IL NUMERO DI ELEMENTI DA PERMUTARE".
004300 DISPLAY "(UNA CIFRA)".
004400 ACCEPT Z.
004500*
004600* si genera la prima permutazione con numeri in ordine
004700* crescente
004800*
004900 MOVE SPACES TO RECORD-LISTA.
005000 PERFORM GEN-PRIMA-PERMUTAZIONE VARYING J FROM 1 BY 1
005100 UNTIL J > Z.
005200
005300 PERFORM PERMUTA.
005400
005500 STOP RUN.
005600
005700
005800 GEN-PRIMA-PERMUTAZIONE.
005900
006000 MOVE J TO LISTA(J).
006100
006200
006300 PERMUTA.
006400
006500 IF Z > A
006600 THEN
006700*
006800* push
006900*
007000 COMPUTE SP = SP + 1,
007100 COMPUTE SAVEK(SP) = K,
007200*
007300* chiamata
007400*
007500 COMPUTE K = Z,
007600 PERFORM SCAMBIO-CHIAMATA-SCAMBIO,
007700*
007800* pop
007900*
008000 COMPUTE K = SAVEK(SP),
008100 COMPUTE SP = SP - 1,
008200
008300 ELSE
008400
008500 DISPLAY RECORD-LISTA.
008600
008700
008800 SCAMBIO-CHIAMATA-SCAMBIO.
008900
009000 IF K >= A
009100 THEN
009200*
009300* scambio di LISTA(K) con LISTA(Z)
009400*
009500 MOVE LISTA(K) TO TEMP,
009600 MOVE LISTA(Z) TO LISTA (K),
009700 MOVE TEMP TO LISTA (Z),
009800*
009900* push
010000*
010100 COMPUTE SP = SP + 1,
010200 COMPUTE SAVEZ(SP) = Z,
010300*
010400* chiamata
010500*
010600 COMPUTE Z = Z - 1,
010700 PERFORM PERMUTA,
010800*
010900* pop
011000*
011100 COMPUTE Z = SAVEZ(SP),
011200 COMPUTE SP = SP - 1,
011300*
011400* scambio di LISTA(K) con LISTA(Z)
011500*
011600 MOVE LISTA(K) TO TEMP,
011700 MOVE LISTA(Z) TO LISTA (K),
011800 MOVE TEMP TO LISTA (Z),
011900*
012000* push
012100*
012200 COMPUTE SP = SP + 1,
012300 COMPUTE SAVEK(SP) = K,
012400*
012500* chiamata
012600*
012700 COMPUTE K = K - 1,
012800 PERFORM SCAMBIO-CHIAMATA-SCAMBIO,
012900*
013000* pop
013100*
013200 COMPUTE K = SAVEK(SP),
013300 COMPUTE SP = SP - 1.
013400
|
|
477.8
Bibliografia
-
Wagener J. L., FORTRAN 77 Principles of Programming, Wiley, 1980, pagine 228..229. [5]
-
Knuth D. E., The Art of Computer Programming - Volume 3 Sorting and Searching, Addison-Wesley, 1973, capitolo 5.
-
Dijkstra E. W., A Discipline of Programming, Prentice-Hall, 1976, capitolo 13.
- Il concetto di locale e di globale: ambito delle variabili
-
-
Wirth N., Principi di programmazione strutturata, ISEDI, 1977, capitolo 12. [1]
-
Moore L., Foundations of Programming with Pascal, Ellis Horwood Limited, 1980, capitolo 10. [3]
-
Ledgard, Nagin, Hueras, Pascal with Style, Hayden, 1979, pagine 126..134. [2]
-
Dijkstra E. W., A Discipline of Programming, Prentice-Hall, 1976, capitolo 10.
-
Nicholls J. E., The Structure and Design of Programming Languages, Addison-Wesley, 1975, capitolo 12.
- La ricorsione
-
-
Arsac J., La construction de programmes structures, DUNOD, 1977, capitoli 2..5.
-
Moore L., Foundations of Programming with Pascal, Ellis Horwood Limited, 1980, capitolo 14.
-
Aho, Hopcroft, Ullman, The Design and Analysis of Computer Algorithms, Addison-Wesley, 1974, pagine 55..60. [4]
-
Ledgard, Nagin, Hueras, Pascal with Style, Hayden, 1979, pagine 134..139.
-
Wirth N., Algorithms + Data Structures = Programs, Prentice-Hall, 1976, capitolo 3.
-
Wagener J. L., FORTRAN 77 Principles of Programming, Wiley, 1980, capitolo 11. [5]
- I linguaggi
-
-
Burroughs Corporation, Computer Management System COBOL, codice 2007266.
-
Burroughs Corporation, Computer Management System Message Processing Language (MPLII) - reference manual, codice 2007563.
Appunti di informatica libera 2006.07.01 --- Copyright © 2000-2006 Daniele Giacomini -- <daniele (ad) swlibero·org>
Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome una_tecnica_per_simulare_la_ricorsione_in_cobol.htm
[successivo]
[precedente]
[inizio]
[fine]
[indice generale]
[indice ridotto]
[translators]
[docinfo]
[indice analitico]