Il pensiero algoritmico prende forma
Un procedimento diventa più facile da discutere quando possiamo riconoscere che cosa accade dopo ogni passo. Il diagramma di flusso espone i percorsi dell’esecuzione; il pseudocodice descrive le operazioni con una notazione testuale controllata. Entrambi permettono di progettare prima di scegliere un linguaggio di programmazione.
Questo capitolo si concentra sulla rappresentazione del controllo: successione dei passi, scelta tra alternative e ripetizione. Useremo un unico esempio, la ricerca della prima occorrenza di un valore in un elenco, per mantenere confrontabili diagramma, pseudocodice e traccia dell’esecuzione. I dati sono illustrativi, non misure sperimentali.
1. Leggere un diagramma: i simboli e le frecce
Un diagramma di flusso di programma è un grafo orientato: i nodi indicano operazioni o decisioni, mentre le frecce stabiliscono i passaggi ammessi. La collocazione di una figura sul foglio aiuta la lettura, ma è la direzione delle frecce a definire il percorso. Due blocchi vicini non sono necessariamente consecutivi.
| Simbolo usuale | Ruolo | Esempio |
|---|---|---|
| Ovale o rettangolo arrotondato | Inizio o fine | Inizio; restituzione del risultato |
| Rettangolo | Elaborazione o assegnazione | i ← i + 1 |
| Parallelogramma | Ingresso o uscita dei dati | Acquisisci elenco e valore cercato |
| Rombo | Decisione | A[i] = x? |
| Freccia | Direzione del controllo | Passa dal confronto all’aggiornamento |
Queste sono convenzioni diffuse nella didattica. ISO 5807 è un riferimento normativo per simboli e convenzioni dei diagrammi informatici; la tabella presenta un sottoinsieme introduttivo, senza sostituire la norma. Un rombo binario deve rendere distinguibili le uscite, per esempio «Sì» e «No». Un incrocio grafico non va lasciato ambiguo: collegamenti e ricongiungimenti devono risultare riconoscibili.
2. Sequenza, selezione e iterazione
Nella sequenza un’operazione segue l’altra. Inizializzare un indice e poi controllare se esistono elementi da esaminare è una sequenza. L’ordine conta: leggere una variabile prima di assegnarle un valore lascia il procedimento incompleto.
Nella selezione una condizione decide quale ramo percorrere. Se il valore esaminato coincide con quello cercato, restituiamo la posizione; altrimenti proseguiamo. Un’esecuzione ordinaria attraversa il ramo determinato dal risultato del confronto, non tutti i rami contemporaneamente. Terminato un ramo, il controllo può ricongiungersi a un passo comune oppure concludere il procedimento.
Nell’iterazione un gruppo di operazioni viene ripetuto. Il diagramma la rende visibile mediante una freccia di ritorno. Bisogna riconoscere la condizione che consente una nuova ripetizione, il corpo del ciclo e l’operazione che modifica lo stato prima del controllo successivo.
Un ciclo MENTRE controlla la condizione prima del corpo: può eseguire zero ripetizioni. Un ciclo RIPETI … FINCHÉ, nella convenzione adottata qui, controlla alla fine ed esce quando la condizione diventa vera: esegue il corpo almeno una volta. Un ciclo PER può esprimere il passaggio attraverso un intervallo o una collezione. Le convenzioni sugli estremi vanno dichiarate: «da 0 a n» non dice da solo se n sia incluso.
3. Un esempio completo: cercare la prima occorrenza
Riceviamo un elenco finito di interi A, di lunghezza n, e un intero x. L’elenco resta invariato durante la ricerca. Numeriamo le posizioni da 0 a n − 1. Il risultato è la prima posizione contenente x, oppure −1 quando x è assente. Il valore −1 è qui un segnale convenzionale, non una posizione da leggere.
Partiamo da i = 0. Prima di leggere A[i] controlliamo i < n. Se non esiste più una posizione valida, restituiamo −1. Se esiste, confrontiamo A[i] con x: l’uguaglianza conclude la ricerca con risultato i; la disuguaglianza porta all’incremento dell’indice e al ritorno al controllo dei limiti.
![Diagramma della ricerca: controlla i minore di n, confronta A[i] con x, restituisce i se uguali o incrementa i; restituisce meno uno quando l’elenco è esaurito.](https://www.alessiopuppi.net/content/uploads/articoli/diagrammi-di-flusso-e-pseudocodice/articolo_diagrammi-di-flusso-e-pseudocodice_1791710287_1ae3e0dd.png)
Il controllo dei limiti precede l’accesso all’elenco. È una scelta strutturale: per un elenco vuoto il primo confronto è già falso e nessun elemento viene letto. Anche dopo l’ultimo elemento non si tenta di accedere alla posizione n.
4. Scrivere il pseudocodice senza nascondere decisioni
Il pseudocodice non ha una sintassi universale. Un corso o un’organizzazione possono fissare proprie regole; occorre usarle in modo coerente. Qui ← significa assegnazione, = indica confronto di uguaglianza, A[i] seleziona l’elemento alla posizione i e RESTITUISCI conclude immediatamente la funzione. I rientri e le parole di chiusura delimitano i blocchi.
FUNZIONE PRIMA_OCCORRENZA(A, x)
n ← LUNGHEZZA(A)
i ← 0
MENTRE i < n FAI
SE A[i] = x ALLORA
RESTITUISCI i
FINE SE
i ← i + 1
FINE MENTRE
RESTITUISCI −1
FINE FUNZIONE
La riga i ← i + 1 legge il valore precedente, aggiunge uno e memorizza il risultato. Non è un’equazione matematica che afferma i = i + 1. Scrivere soltanto «cerca il valore» ometterebbe proprio la parte che vogliamo rendere discutibile: ordine di visita, confronto, avanzamento ed esito in caso di assenza.
La granularità dipende dal destinatario. Possiamo assumere nota l’operazione LUNGHEZZA senza descriverne l’implementazione; non possiamo omettere un’operazione da cui dipende la scelta del risultato. Una sottoprocedura può essere trattata come un singolo passo se ne sono chiariti ingresso, uscita e comportamento.
5. Seguire una traccia, passo dopo passo
Consideriamo A = [12, 5, 9, 5] e x = 5. La traccia registra soltanto gli elementi effettivamente esaminati.
| i prima del confronto | i < 4 | A[i] | A[i] = 5 | Passo successivo |
|---|---|---|---|---|
| 0 | Vero | 12 | Falso | i ← 1; ritorno al controllo |
| 1 | Vero | 5 | Vero | Restituisci 1; fine della funzione |
Le posizioni 2 e 3 non vengono esaminate. La seconda presenza di 5 non cambia il risultato perché l’arresto avviene al primo incontro. Se cerchiamo 7, invece, vengono visitate le quattro posizioni: dopo l’ultimo incremento i vale 4, il controllo è falso e il risultato è −1. Su un elenco vuoto n vale zero e il corpo del ciclo non viene eseguito.
Questo esercizio controlla la coerenza fra rappresentazioni: a ogni decisione del diagramma corrisponde un confronto nel testo; alla freccia di ritorno corrisponde una nuova valutazione di MENTRE; alle uscite corrispondono le restituzioni. È possibile individuare divergenze anche prima di scrivere un programma.
6. Gli errori diventano visibili nel percorso
Se si dimentica l’incremento, una prima posizione che non contiene x viene riesaminata senza avanzare. Se si scrive i ≤ n, il percorso può raggiungere un accesso fuori dall’elenco. Se si sposta RESTITUISCI −1 dentro il ciclo subito dopo il primo confronto negativo, la ricerca dichiara assente un valore che potrebbe comparire più avanti.
Un altro errore consiste nel collocare l’incremento prima del confronto: partendo da zero, si salta il primo elemento. Questi difetti non dipendono dai nomi delle istruzioni di un linguaggio. Dipendono dall’ordine dei passi e dall’appartenenza delle istruzioni ai blocchi.
Diagramma e pseudocodice aiutano a rendere ispezionabili tali decisioni, ma non certificano automaticamente il procedimento. Una rappresentazione chiara può descrivere una soluzione sbagliata. Le tracce sono controlli su casi specifici: non sostituiscono una giustificazione generale quando questa è richiesta.
7. Il ponte verso un linguaggio concreto
Il passo successivo consiste nel tradurre mantenendo il comportamento. In Python la stessa struttura può essere espressa così:
def prima_occorrenza(a, x):
n = len(a)
i = 0
while i < n:
if a[i] == x:
return i
i = i + 1
return -1
La freccia di assegnazione diventa =; il confronto di uguaglianza diventa ==; while e if introducono i blocchi, delimitati dai rientri. Non basta sostituire parole: occorre conservare convenzioni sugli indici, posizione dei controlli e significato delle uscite. In altri linguaggi possono servire tipi espliciti e delimitatori differenti.
L’esempio assume numeri interi e confronti esatti. Cercare numeri reali approssimati, record o testi secondo regole di equivalenza diverse richiede di precisare il confronto. Per programmi concorrenti o interattivi bisogna inoltre rappresentare eventi, modifiche condivise e possibili attese: un singolo percorso sequenziale può non bastare.
8. Che cosa prepara per la programmazione quantistica
Nel corso di informatica quantistica questa competenza servirà a descrivere l’orchestrazione classica: preparare parametri, eseguire una sottoprocedura quantistica, acquisire esiti e decidere il passo successivo. Il collegamento è una traduzione strutturale del controllo classico, non un’equivalenza fisica fra un rombo e un’operazione quantistica.
Un diagramma di flusso non è un circuito quantistico. Quest’ultimo rappresenta operazioni sui registri quantistici; il primo rappresenta il controllo del procedimento descritto. Una condizione su un bit ottenuto da una misura è una decisione classica. Un gate controllato coerentemente da un qubit è un’operazione sullo stato quantistico composto: non equivale a leggere quel qubit e scegliere un ramo classico.
Nei circuiti dinamici una misura intermedia può alimentare una decisione classica che condiziona operazioni successive. L’esecuzione concreta richiede supporto del dispositivo e del runtime, compilazione compatibile e analisi degli errori di gate e lettura. Qui basta acquisire la distinzione: il diagramma rende esplicita la decisione, ma non descrive da solo fase, interferenza o effetti fisici della misura.
9. Un esercizio di traduzione
Modifica il procedimento per restituire l’ultima occorrenza mantenendo la visita da sinistra a destra. Prima cambia il diagramma, poi il pseudocodice. Il suggerimento è conservare una variabile posizione, inizialmente −1, aggiornarla quando il confronto è vero e restituirla soltanto dopo il ciclo. Sull’elenco dell’esempio, cercare 5 deve allora produrre 3.
Controlla l’elenco vuoto, un valore assente e un valore presente più volte. Spiega soprattutto perché una restituzione immediata al primo incontro soddisfa il primo compito e impedisce il secondo. Il risultato didattico è saper collegare ogni requisito a un percorso e ogni percorso alle istruzioni che lo realizzano.