Progettare un algoritmo non è affatto immediato e richiede esperienza e pratica. Di grande aiuto può essere lo studio di algoritmi già risolti, anche da altri, per problemi simili a quello che si sta affrontando (adozione del cosiddetto metodo delle best practices). Alcuni suggerimenti utili per semplificare questo compito sono forniti in un altro post (link: Progettazione di un algoritmo e coding), in questo invece si vuole solo porre l’accento sul fatto che affinché un esecutore possa eseguire un algoritmo con successo, è di fondamentale importanza che quest’ultimo sia descritto solo utilizzando passi che per l’esecutore siano elementari, cioè che esso sia in grado di eseguire.
Occhio all’esecutore!
Quando si progetta un algoritmo oltre a concentrarsi sul problema è fondamentale non perdere mai di vista quali sono le capacità intrinseche dell’esecutore che dovrà eseguirlo e che, ovviamente, nel caso specifico dello sviluppo del software è l’elaboratore elettronico. Il programmatore deve avere ben chiaro quali sono le operazioni e le elaborazioni che per l’elaboratore elettronico possono essere considerate passi elementari e quali, invece, devono essere considerate passi complessi che, quindi, devono essere riscritti in modo da ricondurli a un insieme di passi elementari. Su questo punto ciò che rende la vita del programmatore più semplice, sono i linguaggi di programmazione di alto livello: essi permettono al programmatore di avere a disposizione un esecutore che può essere considerato in grado di fare molte più cose rispetto al caso in cui si debba “comunicare” con esso utilizzando direttamente il suo linguaggio macchina.
A prescindere dal linguaggio di programmazione di alto livello utilizzato, tra i “passi elementari” che un programmatore ha a disposizione, ci sono alcune operazioni fondamentali, quali:
- Acquisire dati in input: l’esecutore sa leggere, almeno dalla periferica di input standard – la tastiera.
- Visualizzare dati in output: l’esecutore sa scrivere, almeno sulla periferica di output standard – il monitor;
- Capacità di conservare (scrivere e leggere) dati nella memoria centrale assegnando valori alle variabile che vengono in essa allocate (create occupando un certo numero di locazioni di memoria RAM) : con l’operatore di assegnazione, l’esecutore è in grado di memorizzare i dati nella memoria RAM e di recuperarli;
- Operazioni aritmetiche: si dispone almeno degli operatori aritmetici di base – somma, sottrazione, prodotto e divisione.
Tutti i linguaggi di programmazione di alto livello, inoltre, mettono a disposizione tre strutture di controllo per il controllo del flusso di esecuzione di un algoritmo, ossia:
- la sequenza;
- la selezione (o alternativa);
- la ripetizione (o iterazione o ciclo).
Queste tre strutture di controllo sono alla base della programmazione strutturata che si fonda sul famoso teorema di Böhm e Jacopini, che prende il nome da due informatici italiani con il quale hanno dimostrato che queste tre strutture di controllo sono sufficienti per descrivere la soluzione di un qualunque problema, comunque complesso, purché risolvibile. Direttamente all’uso di queste strutture, inoltre, sono legate altre operazioni elementari, anche queste sempre disponibili con tutti i linguaggi di programmazione di alto livello:
- Esecuzione di confronti tra valori dello stesso tipo tramite gli operatori di confronto maggiore, minore, uguale, diverso, ecc., che sempre danno come risultato un valore booleano (vero/falso). Essi sono indispensabili per costruire enunciati logici (o condizioni logiche);
- Possibilità di legare tra loro due o più enunciati tramite i connettivi logici, almeno AND, OR e NOT.
Oltre a quelle elencate, inoltre, il programmatore ha a disposizione altre istruzioni in grado di compiere operazioni più complesse, che possono più o meno dipendere dal particolare linguaggio di programmazione di alto livello utilizzato, per esempio è questo il caso delle funzioni di libreria specifiche messe a disposizione dal linguaggio di programmazione.
Per l’applicazione di questi concetti si rimanda al seguente esempio: Il maggiore di una sequenza di numeri.