Indice generale
1.Introduzione .....................................................................................................................................2
2.Algoritmi e Informatica....................................................................................................................3
2.1.Che significa risolvere un problema?............................................................................................3
2.2.Algoritmi e Programmi..................................................................................................................4
3.Rappresentazione degli algoritmi.....................................................................................................7
3.1.La descrizione degli algoritmi – alcuni concetti............................................................................8
3.2.Algoritmi Diagrammi di flusso e pseudocodifica.......................................................................14
4.Strutture di controllo.......................................................................................................................17
5.Le strategie per la risoluzione di problemi.....................................................................................21
5.1.Interpretazione (comprensione del problema).............................................................................22
5.2.Il Modello (modellizzazione della situazione)............................................................................23
5.3.Procedimento risolutivo...............................................................................................................24
Conoscere l'argomento..............................................................................................................24
Sfruttare l'esperienza.................................................................................................................24
Procedere a ritroso....................................................................................................................25
Scomporre i problemi................................................................................................................25
5.4.Esecuzione...................................................................................................................................26
5.5.Verifica dei risultati.....................................................................................................................28
1
ALGORITMI
La teoria è quando si sa tutto e niente
funziona.
La
pratica
è
quando
tutto
funziona e nessuno sa il perchè. In questo
caso abbiamo messo insieme la teoria e la
pratica: non c'è niente che funziona...e
nessuno sa il perchè!
(Albert Einstein)
1.
Introduzione
La storia dell’informatica non riguarda solo lo sviluppo degli strumenti di calcolo e del moderno
computer, ma include anche lo studio dei procedimenti di calcolo per risolvere problemi (sia
quelli eseguiti dall’uomo che quelli eseguiti automaticamente dagli strumenti di calcolo).
In
informatica, i procedimenti di calcolo vengono comunemente denominati algoritmi.
In modo informale possiamo dire che un algoritmo è una procedura di calcolo descritta in modo
sufficientemente preciso atta a risolvere un determinato problema.
Nel corso dei secoli la concezione e il modo di descrivere gli algoritmi è cambiato in modo
significativo e oggi è possibile scrivere algoritmi che possono essere eseguiti automaticamente
su una macchina.
Utilizziamo algoritmi nella vita quotidiana tutte le volte che, ad es., seguiamo le istruzioni per il
montaggio di una apparecchiatura, per impostare il ciclo di lavaggio di una lavastoviglie, per
prelevare contante da uno sportello Bancomat, per la cena, per fare il bagno, per la sveglia,
ecc.
Esempio: Algoritmo Risveglio
1.Alzarsi dal letto
2.Togliersi il pigiama
3.Fare la doccia
4.Vestirsi…
5…….
Quindi il concetto di algoritmo non è per forza legato ad azioni svolte da una macchina , ma ha
un significato molto più ampio.
Il calcolatore ha 60 anni… gli algoritmi hanno 4000 anni!
Primi algoritmi babilonesi ed egiziani. (2000-1600 A.C.)
Tavolette babilonesi forniscono ‘algoritmi’ nella forma di ripetuti esempi di sequenze di operazioni.
Dalla sequenza di esempi si può inferire l’algoritmo.
In questo caso si poteva trattare ad esempio di sequenza di operazioni matematiche per il calcolo
di un risultato.
2
2.
Algoritmi e Informatica
Il concetto di algoritmo presuppone l’esistenza di un esecutore, cioè colui che deve
effettivamente compiere le operazioni. L’esecutore è spesso, ma non sempre, il computer.
Benché la definizione di algoritmo sia indipendente dall’esecutore, esso è spesso associato al
calcolatore elettronico. Un algoritmo deve essere pertanto definito in modo che possa essere
interpretato ed eseguito correttamente dal calcolatore.
2.1.
Che significa risolvere un problema?
A partire da un insieme di dati iniziali (Input) l'algoritmo compie una serie di azioni su di essi
fino a produrre un risultato finale (output).
Dati iniziali e finali (input e output):i dati di input sono i dati che vengono posti in ingresso(es
da tastiera) e i dati di output sono inviati in uscita dal calcolatore verso l'esterno.
L'elaborazione viene descritta dall'algoritmo ed eseguita da un esecutore. Un esecutore è il
soggetto che compie le azioni descritte dall'algoritmo.
Es: torta di carote
Vogliamo essere capaci di specificare la strategia seguita dal passo di elaborazione in modo da
farla eseguire ‘automaticamente’ dal computer quindi dobbiamo riuscire a descrivere
accuratamente i vari passi della soluzione attraverso azioni che l'esecutore è in grado di
effettuare e con un linguaggio che è in grado di comprendere.
3
2.2.
Algoritmi e Programmi
Poiché vogliamo trattare gli algoritmi in ambito informatico lo schema successivo descrive il
procedimento e gli agenti coinvolti.
Abbiamo già chiarito il significato di input e output. Sono i dati forniti forniti in ingresso al
calcolatore. Esempio: se si tratta di fare la somma di due numeri, i dati di input saranno i due
numeri chiamiamo a1 e a2 che voglio sommare.
L'elaborazione è il procedimento risolutivo che deve prima essere pensato e poi essere
eseguito. L'algoritmo viene descritto dunque da un agente umano.
Per poter essere eseguito su una macchina deve essere codificato in un linguaggio
comprensibile al calcolatore. Dunque un programma è la codifica in un linguaggio di
programmazione del procedimento risolutivo. Il programma viene eseguito dal calcolatore.
Diamo adesso le definizioni formali.
Def. Algoritmo Per algoritmo si intende una sequenza finita di azioni elementari e non
ambigue che definiscono una sequenza di operazioni che possono essere eseguite da un
opportuno esecutore e mediante le quali si risolve una classe di problemi.
Risolvere un problema significa individuare un procedimento che permetta di arrivare al
risultato partendo da dati noti.
Per istruzione elementare si intende una istruzione non ulteriormente scomponibile in relazione
all'esecutore. Cioè una istruzione elementare per un determinato esecutore può non esserlo
per un altro. Richiameremo questo concetto successivamente in qualche esempio pratico.
Def. Programma. Il programma è la rappresentazione di un algoritmo utilizzando un
linguaggio non ambiguo e direttamente comprensibile dal computer, cioè un linguaggio di
programmazione.
4
(Def) Istruzione. Le singole azioni del procedimento risolutivo, codificate in linguaggio di
programmazione prendono il nome di istruzioni
E' possibile elencare alcune proprietà e caratteristiche che un algoritmo deve possedere. Un
algoritmo deve essere:
•
generale: il metodo deve risolvere una classe di problemi e non un singolo problema
(ad esempio deve essere in grado di calcolare l'area di tutti i triangoli e non solo quella
di un particolare triangolo)
•
finito: le istruzioni che la compongono devono essere in numero finito.
•
completo: deve contemplare tutti i casi possibili del problema da risolvere (per esempio
nel calcolo della divisione deve tenere conto anche dei casi 0/0 e a/0 e dire cosa
succede in questi casi)
•
non ambiguo: ogni istruzione deve essere definita in modo preciso ed univoco, senza
alcuna ambiguità sul significato dell’operazione. Ossia l'esecutore deve poter
interpretare in modo univoco ogni singola azione
•
eseguibile (o realizzabile): deve esistere un agente di calcolo in grado di eseguire ogni
istruzione in un tempo finito
•
limitato nel tempo: il numero di volte che ogni azione viene eseguita deve essere finito.
Cioè deve avere durata limitata nel tempo.
n.b. L'ultimo caso è un caso in cui spesso i principianti, ma a volte anche i veterani, cadono in
errore. E' il caso in cui si generano algoritmi che vanno in “loop” cioè non terminano mai la loro
l'esecuzione. Pertanto quando ci troveremo in questa situazione dovremo interrompere
brutalmente e forzatamente l'esecuzione del programma.
Esempio: supponiamo di voler calcolare la somma di 1+2+3+4+5+... fino a
quando la somma è superiore a 50. Allora ripeto 1+2+3+4+5+6+7+8+9+10 e
mi fermo qui.
Supponiamo di cambiare leggermente il problema in:calcolare la somma di
1+2+3+4+5+... fino a quando la somma è inferiore a 0. Questa condizione non
potrà mai avverarsi, pertanto in questo caso sommerei 1+2+3+4+.....all'infinito.
Occorre quindi porre attenzione alla condizione di STOP di un procedimento.
Così strutturato, un algoritmo permette di risolvere il problema per cui è stato pensato.
Abbiamo visto che per esemplificare il concetto di algoritmo si usano gli esempi delle ricette di
cucina o altri esempi del quotidiano, ma gli esempi più significativi si trovano in matematica e
in informatica, dove sequenze anche molto complicate di azioni opportunamente codificate
possono servire per comunicare tra studiosi particolari procedimenti oppure per far compiere ai
5
computer determinate azioni.
Ma insomma, una ricetta è proprio un algoritmo?
… NO, ovvero è molto simile ma con due importanti differenze:
La sequenza di azioni contiene spesso degli elementi di
ambiguità risolti da un esecutore intelligente
es: spesso non si specificano gli strumenti da utilizzare, confidando che l’esecutore umano
sbatta le uova nel posto giusto
es: sale q.b.
Non tutti i possibili casi vengono specificati
es: è chiaro che se c’e’ puzza di bruciato conviene spegnere il forno, anche se la ricetta non lo
specifica (si confida nelle capacità deduttive dell’esecutore)
Esempi di algoritmi:
addizione o moltiplicazione di più numeri a più cifre
calcolo delle soluzioni di una equazione di primo grado
calcolo del perimetro e dell'area di una figura geometrica
etc
Un'altra cosa importante da notare è che, anche nel nostro quotidiano, un problema può avere
più soluzioni, alcune saranno migliori altre peggiori. Per esempio potrei risolvere il problema di
andare da Roma a Milano seguendo diverse soluzioni (tragitti).
Nello stesso modo un problema può essere risolto da più algoritmi.
In questo caso diremo che Due algoritmi si dicono equivalenti se risolvono lo stesso problema.
Oppure in modo più preciso: Due algoritmi si dicono equivalenti se in corrispondenza degli
stessi dati di input producono gli stessi dati di output.
6
3.
Rappresentazione degli algoritmi
Ma come si scrive un algoritmo?
In modo informale posso dettagliare i vari passi del procedimento, come le istruzioni per fare la
torta o per montare un armadio o per andare da Roma a Milano.
In informatica abbiamo però bisogno di eliminare le ambiguità che potrebbero derivare dall'uso
del linguaggio naturale che è quello che usiamo ogni giorno. Per esempio considerando una
ricetta di cucina, la frase “sale q.b” non è univocamente interpretabile e precisa. Potremmo
dire che è abbastanza ambigua e soggettiva.
Poiché abbiamo elencato la non-ambiguità come una delle caratteristiche che un algoritmo
deve possedere occorre inventarsi un formalismo che consenta di scrivere un procedimento
(algoritmo) in modo preciso e non ambiguo.
Uno algoritmo può essere rappresentato in vari modi: formula, sequenza di istruzioni, disegno,
a parole... etc. I formalismi fanno uso di una serie di simboli base e di regole per la
combinazione di tali simboli. Esempio:
Algoritmo
Simboli base
I metodi da usare per rappresentare in modo efficiente ed esaustivo gli algoritmi vengono detti
formalismi di codifica poiché rappresentano l’algoritmo mediando tra il semplice linguaggio
comune e il formale linguaggio matematico; ne esistono di diversi tipi con la caratteristica
comune di essere ben definiti e non ambigui.
Negli anni si sono sviluppate varie tecniche di rappresentazione, ne descriveremo due: i
diagrammi di flusso o flow-chart e la pseudocodifica.
7
3.1.
La descrizione degli algoritmi – alcuni concetti
Come detto precedentemente è opportuno adottare, per descrivere un algoritmo, una forma
ordinata e precisa di esposizione che ci metta al riparo dall’ambiguità del linguaggio naturale.
Descrivere un algoritmo in linguaggio naturale ha il vantaggio di essere patrimonio comune ad
un vasto numero di persone, ma ha lo svantaggio di essere: non preciso, complesso e
inadeguato. Prima di passare alla descrizione (o rappresentazione degli algoritmi, cominciamo
a formalizzare alcuni concetti.
Variabili
La variabile è un oggetto dotato di una identità (nome), di uno stato (contenuto o valore), e di
un tipo (tipo di contenuto e possibili operazioni su di esso).
7
Contenuto
SOMMA
Nome
• Il contenuto di una variabile può variare durante il processo di esecuzione
• Il nome di una variabile è composto da una lettera seguita da un numero arbitrario di
caratteri: a, b1, C24, pippo, x24.
Una variabile può contenere solo valori appartenenti ad un unico tipo di dato:
• variabili intere: solo valori interi (1, 50, 1002)
• variabili reali: solo valori reali (1.5, 3.4, 2053.76)
• variabili carattere: solo caratteri (‘a’, ‘c’, ‘1’)
Costanti
Una costante non si modifica durante il processo di esecuzione. Esempi di costanti sono:
1, 5, 3890
2.3, 3.5, 234.33
‘a’, ‘f’, ‘3’
“ciao”
costanti intere
costanti reali
costanti carattere
costante stringa
Operazione di assegnamento
L’operazione di assegnamento permette di cambiare lo stato di una variabile, ovvero assegna
un valore ad una variabile. La sintassi dell’operazione di assegnamento è la seguente:
nome_variabile ← espressione
Esempi di assegnamento validi sono i seguenti:
a←1
a←a+1
b←c+3
c←’b’
pippo←4.
8
L’operazione di assegnamento funziona nel modo seguente:
1. Si valuta l’espressione a destra del simbolo ←
2. si assegna il valore trovato in (1) alla variabile che sta a sinistra del simbolo ←
Un concetto importante da ricordare è che l’operazione di assegnamento è distruttiva: il
valore contenuto nella variabile precedentemente ad una operazione di assegnamento è
definitivamente perduto. Se la variabile x contiene 5 dopo x←7 del valore 5 non si ha più
memoria.
x←7
5
7
x
x
Problema: “date due variabili a e b scambiarne il contenuto”
La soluzione immediata, ma sbagliata è la seguente:
1. a←b
2. b←a
Infatti essendo l’assegnamento distruttivo il valore di viene irrimediabilmente perduto e alla
fine delle due operazioni troveremo che sia a che b contengono lo stesso valore e cioè il valore
iniziale di b.
La soluzione corretta prevede l’uso di una terza variabile, detta variabile di comodo, dove
salvare il contenuto della variabile a prima di assegnarli il valore di b:
1. aiuto←a
2. a←b
3. b←aiuto.
Tutte le variabili prima di poter essere utilizzate in una espressione devono essere inizializzate,
cioè devono contenere un valore. Una variabile non inizializzate è una variabile senza valore e
utilizzarla è un errore, ad esempio la sequenza di istruzioni:
1. a←b+1
2. b←5
è errata poiché in (1) la variabile b non è inizializzata, è senza contenuto.
Ingresso e Uscita
Un algoritmo deve poter comunicare con il mondo esterno per ricevere i dati in ingresso e
poter
restituire
i
risultati
dell’elaborazione
in
uscita.
Le
istruzioni
di
ingresso/uscita
(input/output) sono usate per comunicare con il mondo esterno.
9
L’istruzione di ingresso è:
Leggi nome_var1,nome_var2,.......,nome_varn
dove
nome_var1,nome_var2,.....,nome_varn è la lista delle variabili di ingresso.
L’istruzione di uscita è:
Scrivi espr1,espr2,......,esprn
dove
espr1,espr2,.....,esprn è la lista delle espressioni in uscita.
Come si può notare per la Leggi utilizziamo solo variabili, mentre per la Scrivi utilizziamo
delle espressioni, ciò è dovuto al fatto che l’operazione di scrittura non ha alcun effetto sulla
lista dei parametri che utilizza, mentre l’operazione di lettura ha lo stesso effetto
dell’operazione di assegnamento.
1. a←1
2. b←2
3. Scrivi a,b
La sequenza di istruzioni sopra descritte permette di trasmettere all’esterno i valori di a e b (1
e 2), che rimangono invariati anche dopo la loro trasmissione. Lo stesso effetto non si ha
quando utilizziamo le istruzioni di lettura:
1.
2.
3.
4.
a←1
b←2
Leggi a,b
Scrivi a,b
I valori di a e b vengono modificati dalla istruzione di lettura, infatti il risultato in uscita sarà
dato dai valori inseriti dall’utente.
Ricordiamo infine che l’istruzione Leggi ha lo stesso effetto dell’operazione di assegnamento e
quindi può essere utilizzata per inizializzare le variabili.
Espressioni
Tutti sanno che:
(3X-Y)(X+2)
è una espressione aritmetica dove X e Y sono le variabili e 3 e 2 sono le costanti. Sappiamo
anche che fino a quando non si attribuiscono particolari valori alle variabili essa non
rappresenta alcun valore e che, quando affermiamo che X vale 1 e Y vale 2 e operiamo un
processo di valutazione l’espressione vale 3. In seguito supporremo che l’esecutore disponga
di un valutatore che riceve un’espressione aritmetica, il suo ambiente di valutazione (i valori
delle variabili) e restituisce il risultato.
In informatica tutti gli operatori devono essere esplicitati, non possono essere sottintesi:
(3X-Y)(X+2)
NO
(3*X-Y)*(X+2)
SI
10
Gli operatori sono simboli speciali che rappresentano elaborazioni di tipo matematico, quali la
somma e la moltiplicazione. I valori che l'operatore usa nei calcoli sono chiamati operandi.
Esempi
di
operatori
aritmetici
che
utilizzeremo
sono:
+(somma),
-(differenza),
*(prodotto), /(divisione(intera), %(modulo -cioè resto della divisione tra due
numeri) etc...
Un'espressione è una combinazione di operandi(valori, variabili) e operatori.
Esempio di espressioni aritmetiche valide sono
•
•
•
•
•
•
3
X
3+Y
X+Y*2
(3+X)/4
X+Y2 (Corretta se si suppone Y2 nome di una variabile)
Dove la correttezza della espressione è data dalla giustapposizione di operandi e operatori
come già la conosciamo dalla matematica.
Espressioni non valide sono:
•
•
•
•
+
/+
3X+Y
X*+Y2
Mancano gli operatori
Mancano gli operatori e non posso giustapporre due operandi
Non posso giustapporre due operandi
Non posso giustapporre due operatori
Le espressioni devono essere scritte in questo modo per evitare delle ambiguità.
Esercizio:
•
•
X5 è una variabile o una espressione?
4Y è una espressione o un nome non valido di variabile?
Espressioni logiche (Condizioni o Termini Booleani)
Le condizioni vengono dette anche "termini (o espressioni) booleane", dal nome del
matematico inglese Boole che per primo introdusse l'impiego di simboli per rappresentare gli
operatori logici.
Una condizione (o espressione logica o termine booleano) può essere più precisamente
descritto come una formula (equazione, disequazione o altro tipo di relazione).
Ese:
a>3
4<=7+2
x=y
sono esempio di espressioni logiche. Le espressioni logiche producono come risultato due soli
valori {V,F} cioè (vero/falso; true/false; 0/1)
Un'espressione logica è formata da operatori (variabili o valori costanti) e operatori relazionali.
Gli operatori relazionali sono gli operatori di confronto che già conosciamo dalla matematica
> (maggiore)
>=(maggiore o uguale)
<(minore)
<=(minore o uguale)
!=(diverso)
= (uguale)
11
Le espressioni logiche semplici possono essere combinate per costruire espressioni logiche
composte. La combinazione si realizza attraverso gli operatori logici che sono:
•
•
•
NOT
AND
OR
(citiamo solo questi per il momento)
L'operatore AND significa che l’espressione condizionale è vera se e solo se sono vere
entrambe le condizioni.
Es: 4>5 and 3>2 è falsa
5>4 and 3>2 è vera
L'operatore OR significa che l’espressione condizionale è vera se
condizioni è vera.
Es: 4>5 and 3>2 è vera
5<4 and 3<2 è falsa
almeno una delle due
L'operatore NOT anteposto davanti ad una espressione logica nega il valore dell'espressione.
Es: not(4>5) è falsa
not (1>3) è vera
Possiamo ricavare le tabelle di verità che descrivono quanto detto. Date due espressioni
logiche x e y, le seguenti tabelle descrivono il valore dell'espressione finale in base ai valori
delle espressioni di partenza (x e y).
x
FALSO
FALSO
VERO
VERO
y
FALSO
VERO
FALSO
VERO
x and y
FALSO
FALSO
FALSO
VERO
x
FALSO
FALSO
VERO
VERO
y
FALSO
VERO
FALSO
VERO
x or y
FALSO
VERO
VERO
VERO
x
VERO
FALSO
not x
FALSO
VERO
12
Precedenza tra gli operatori:
Operatore
Nome
Not
Not
*
/
%
Moltiplicazione
Divisione
Modulo
+
-
Addizione
Sottrazione
<
<=
>
>=
Minore
Minore Uguale
Maggiore
Maggiore Uguale
=
!=
Uguale
Diverso
AND
AND
OR
OR
<--
Assegnamento
Esempio:
a AND NOT b OR c
L’esempio precedente è ambiguo perché potrebbe essere interpretato nei modi seguenti:
( a AND (NOT b)) OR c
a AND ( (NOT b) OR c)
a AND ( NOT ( b OR c))
Per risolvere l’ambiguità o si usano obbligatoriamente le parentesi oppure si assume un ordine
di priorità degli operatori, quello usuale è NOT, AND, OR. Questo vuol dire che nel valutare una
espressione prima si valutano i NOT poi gli AND e poi gli OR, questo corrisponde alla prima
interpretazione riportata. Questo è anche l’ordine con cui si risolve comunemente l’ambiguità
nelle espressioni algebriche numeriche con gli operatori -, × e + infatti l’espressione a × –b +
c viene comunemente interpretata come ( a × ( - b ) ) + c.
13
3.2.
Algoritmi Diagrammi di flusso e pseudocodifica
Passiamo adesso a descrivere gli strumenti per rappresentare gli algoritmi.
Vi sono vari strumenti per rappresentare gli algoritmi, il più noto, e anche il più vecchio, è il
Diagramma a Blocchi. Negli anni ’60 erano praticamente l’unico strumento preso in
considerazione per esprimere un algoritmo. Gli anni ’70 hanno notevolmente sminuito
l’importanza della diagrammazione, sono infatti sorti nuovi strumenti che hanno contribuito ad
evidenziare alcuni difetti di questa forma espressiva, soprattutto sotto la spinta di una nuova
generazione di linguaggi di programmazione.
Noi analizzeremo due strumenti di rappresentazione:
• Diagrammi a Blocchi
• Notazione Lineare Strutturata (o pseudocodifica)
La differenza tra i due:
flow-chart - strumento grafico, ha un maggiore impatto visivo
pseudocodifica - utilizza un linguaggio descrittivo costituito da un insieme di parole
(sottoinsieme del linguaggio naturale) e da regole sintattiche per costruire le frasi. Piu rapido
per appuntare bozze di soluzioni. Semplice (…) passare dalla descrizione in pseudo codice alla
effettiva descrizione in un linguaggio di programmazione
Ricordiamo che un algoritmo è una procedura di calcolo costituita da un numero finito di passi
elementari e che termina, producendo la soluzione del problema, dopo aver effettuato un
numero finito di operazioni. Con “passi elementari” si intendono delle istruzioni che facciano
diretto riferimento alle capacità di base dell’esecutore automatico a cui viene fornito l’algoritmo
per risolvere il problema. Tale esecutore automatico, come è noto, oltre a saper eseguire le
quattro operazioni aritmetiche (somma, sottrazione, divisione e moltiplicazione) è in grado di
memorizzare i dati in alcune variabili di memoria identificate da un nome e di eseguire le
seguenti sette istruzioni fondamentali che possiamo ritrovare in tutti i linguaggi di
programmazione
“imperativi/procedurali”
(spiegheremo
meglio
il
significato
di
imperativo/procedurale):
begin (o inizio): inizia l’esecuzione dell’algoritmo.
assegnamento: consente di attribuire ad una variabile un valore costante, il valore
memorizzato in un’altra variabile o il risultato di un’espressione aritmetica tra valori costanti o
valori contenuti in altre variabili (es.: “a = 3”, “a = b +3c”, ecc.);
leggi (operazione di ingresso o input): consente all’esecutore di acquisire dall’esterno
un’informazione e di memorizzarla in una variabile di memoria (es.: “leggi a”);
scrivi (operazione di uscita o output): consente all’esecutore di visualizzare/stampare
all’esterno un dato costante, un valore memorizzato in una variabile o il risultato di
un’espressione aritmetica che coinvolga valori costanti o variabili (es.: “scrivi Sì”, “scrivi 15”,
“scrivi a”, “scrivi a +7b”, ecc.);
14
se... allora... altrimenti: consente all’esecutore di valutare un’espressione booleana (una
condizione logica) il cui valore può essere solo “vero” o “falso”; in base al risultato della
valutazione della condizione, vengono eseguite delle istruzioni oppure, in caso contrario, delle
altre (es.: “se a > 0 allora a = a −1 altrimenti a = 20”);
ripeti...finchè (oppure esegui mentre...ripeti): consente all'esecutore di ripetere un
insieme di azioni per un certo numero di volte in base al valore di una condizione logica.
stop (o fine): termina l’esecuzione dell’algoritmo.
Flow_chart
Ad ognuna delle precedenti istruzioni elementari corrisponde un simbolo con cui è possibile
costruire una “rappresentazione grafica” dell’algoritmo, ossia un diagramma di flusso. Ogni
diagramma di flusso ha un unico punto di inizio ed un unico punto terminale: entrambe queste
istruzioni (start e stop) sono rappresentate da un ellisse; nella pseudo-codifica di un algoritmo
espressa come una sequenza di istruzioni elementari l’istruzione start è implicita visto che
l’algoritmo inizia sempre dal primo passo della pseudo-codifica. Le istruzioni di assegnazione,
in
generale
le
più
frequenti
negli
algoritmi,
sono
rappresentate
all’interno
di
un
rettangolo,mentre le operazioni di input e di output (leggi e scrivi) sono rappresentate con dei
parallelogrammi. Le condizioni sono espresse all’interno di rombi ed infine le ripetizioni (ripetifinchè...) sono rappresentati con delle frecce che ritornano su blocchi precedenti.
Notazione Lineare Strutturata (o pseudocodifica)
Si utilizzano le seguenti parole chiave:
INIZIO/FINE (o BEGIN/END): per iniziare e terminare l'algoritmo
LEGGI/SCRIVI: per leggere da input e scrivere su output rispettivamente
← per l'assegnamento
SE...ALLORA....ALTRIMENTI...FINE_SE: per eseguire delle azioni condizionate dal valore di
verità di una espressione logica
RIPETI FINCHE' (o MENTRE..ESEGUI): Per eseguire delle iterazioni in base al valore di una
condizione logica.
15
Esempio:Calcolo della somma tra due numeri interi x, y
Algoritmo somma1
0.INIZIO
1.LEGGI (x,y)
2.somma<--x+y
3.SCRIVI (somma)
4.FINE
Algoritmo somma2
0.INIZIO
1.LEGGI (x,y)
2.SCRIVI (x+y)
3.FINE
Esempio:Calcolo del massimo tra due numeri interi x, y
Algoritmo massimo1
0.INIZIO
1. LEGGI (x,y)
2. SE x>y ALLORA
2.1. massimo<--x
ALTRIMENTI
2.2. massimo<--y
FINESE
3. SCRIVI(“il massimo è”, massimo)
4. FINE
Algoritmo massimo2
0. INIZIO
1. LEGGI (x,y)
2. diff<--x-y
3. SE diff>0 ALLORA
3.1. massimo<--x
ALTRIMENTI
3.2 massimo<--y
FINESE
4. SCRIVI(“il massimo è”, massimo)
5. FINE
16
4.
Strutture di controllo
In un algoritmo sono normalmente presenti sequenze di passi in successione, ma anche passi
decisionali che servono a controllare la particolare sequenza dinamica che deve essere eseguita
dall’esecutore per risolvere uno specifico caso di ingresso.
Le istruzioni di controllo servono per influenzare il flusso di esecuzione di un programma.
Tramite le istruzioni di controllo è possibile “compiere scelte” all’interno di un programma
La scelta avviene valutando il valore di verità su di una condizione.
Si può dimostrare che per descrivere qualunque algoritmo sono sufficienti solo tre tipologie di
strutture:L'istruzione di sequenza, l’istruzione di selezione e l’istruzione iterativa.
Lo schema che alla fine è emerso, detto "programmazione strutturata", si propone di dare
l'aspetto di un flusso ordinato tra un inizio ed una fine a programmi che di per sé sarebbero
intricati. Il modello è il "programma sequenziale", nel quale si applicano le varie operazioni una
di seguito all'altra, in modo ordinato, senza alternative possibili. Tuttavia (come si evince dagli
esempi precedenti) la semplice sequenza non può esprimere tutta la potenza degli algoritmi
poiché questa è essenzialmente contenuta nella capacità di scegliere tra due alternative. Come
si possono dunque conciliare queste due esigenze?
L'idea è semplicissima: basta imitare il linguaggio naturale. In un linguaggio naturale un
algoritmo è già espresso in una forma strutturata che corrisponde allo "svolgimento temporale"
di una particolare computazione, quello cioè che si chiama un "processo". In un linguaggio
naturale le costruzioni utilizzate sono "fai questo ... , dopo fai quello ... ", "se ... fai questo ...
altrimenti fai quello ... ", "finché ... fai così ... " oppure "ripeti 5 volte questo ... ", che sono
proprio le costruzioni di "controllo del flusso", sequenza, alternativa e ciclo, che saranno al
centro di tutta la nostra discussione.
17
Sequenza: Istruzioni semplici di Ingresso,
Uscita, Assegnazione
Selezione: Esprime la scelta tra due possibili
azioni mutuamente esclusive
Ciclo o Iterazione: Esprime la ripetizione di
un’azione
A questo risultato si arrivò nel 1966 con il teorema di
Jacopini-Böhm: ogni programma (di
Turing) può essere espresso con sequenze, alternative o cicli di blocchi di istruzioni. Il seguito
chiariremo e approfondiremo i termini della questione soprattutto riguardo al fondamentale
concetto di blocco.
18
SEQUENZA
0. INIZIO
1. Alzarsi dal letto
2. Togliersi il pigiama
3. Fare la doccia
4. Vestirsi
5. Fare colazione
6. Prendere il bus per andare a scuola
7. FINE
ALTERNATIVA
0. INIZIO
1. Alzarsi dal letto
2. Togliersi il pigiama
3. Fare la doccia
4. Vestirsi
5. Fare colazione
6. SE piove ALLORA
6.1
Prendere ombrello
7. Prendere il bus per andare a scuola
8. FINE
0. INIZIO
1. Alzarsi dal letto
2. Togliersi il pigiama
3. Fare la doccia
4. Vestirsi
5. Fare colazione
6. SE sciopero mezzi pubblici ALLORA
6.1. Prendere macchina
7. ALTRIMENTI
7.1. Prendere il bus
8. FINE
19
RIPETIZIONE (ITERAZIONE)
0. INIZIO
1. Alzarsi dal letto
2. Togliersi il pigiama
3. Fare la doccia
4. Vestirsi
5. Fare colazione
6. MENTRE piove
6.1. Restare in casa
7. Prendere il bus per andare a scuola
8. FINE
Le strutture di controllo si possono combinare tra loro in vari modi, in sequenza o annidando
una struttura dentro l'altra. Esempio:
Come si mette l’olio nell’auto
apri il serbatoio dell'olio
ripeti
prendi una lattina;
se chiusa allora aprila
ripeti
versa olio
se cade allora
pulisci
finché c’è olio nella lattina
finché il livello è sotto il minimo
Fino a questo momento abbiamo visto come “spezzettare” la descrizione di un procedimento
risolutivo in azioni semplici ed elementari. E ci siamo sforzati, con l'aiuto di esempi presi dal
nostro quotidiano, di tradurre i nostri comportamenti come
composizione di microazioni
opportunamente combinate tra loro.
Nei paragrafi successivi vedremo come affrontare invece la soluzione di problemi più complessi
e ci concentreremo sulle tecniche per la soluzione dei problemi più complessi.
La risoluzione di un problema complesso richiede un approccio metodologico altrimenti si
rischia di andare “alla cieca” e tirare fuori soluzioni non ottimali o inefficienti.
Un buon algoritmo è come un coltello affilato – fa esattamente ciò che si suppone debba fare,
applicando una quantità minima di forza; mentre usare un algoritmo sbagliato per risolvere un
problema è come tagliare una bistecca con un giravite: si può anche arrivare ad un risultato
accettabile, ma facendo sicuramente uno sforzo ben maggiore di quanto non fosse necessario.
Inoltre il risultato non si può certo definire elegante.
20
5.
Le strategie per la risoluzione di problemi.
Scrivere un algoritmo dunque significa scrivere un procedimento risolutivo. Per poter arrivare a
risolvere un problema è necessario adottare alcune strategie per la risoluzione.
Quando ci si accinge a risolvere un problema, per giungere rapidamente ad una soluzione
sembrerebbe sufficiente conoscere l’argomento, saper sfruttare l’esperienza accumulata e
possedere le opportune risorse. Spesso, però, ci si accorge che, pur possedendo una certa
abilità e le competenze necessarie, non si riesce a raggiungere la meta.
Quante volte ad esempio, vi è capitato in un compito in classe di non riuscire a risolvere un
problema pur avendo a disposizione tutte le formule necessarie riportate sul fogliettino?
Una considerazione che aiuta a ridurre le possibilità di insuccesso è sicuramente legata al
metodo con cui si affronta il problema: analizzare in modo sistematico la situazione, infatti,
anche se di per sé non porta alla soluzione, permette di isolare i nodi di difficoltà e di
conseguenza favorisce, sfruttando al meglio le capacità del risolutore, quanto meno un
avanzamento dei lavori.
Anche
se
quando
si
affrontano
problemi
semplici
molto
spesso
non
ci
si
accorge
dell'importanza di un approccio sistematico, poiché le prime fasi dell'analisi vengono svolte in
modo inconscio e quasi automatico, quando il problema presenta un certo grado di complessità
risulta quasi naturale affrontarlo con metodo.
In ogni caso è molto importante effettuare un buon lavoro di preparazione.
Naturalmente qualsiasi metodo sistematico di analisi non va considerato alla stregua di una
camicia di forza in cui imbrigliare intuito e fantasia, ma solo come un valido strumento da
affiancare ad essi.
Descriviamo di seguito come affrontare la soluzione dei problemi. La nostra strategia si
compone di varie fasi che sono descritte nel grafico seguente.
1. interpretare l’enunciato del problema e definire gli obiettivi da realizzare;
2. individuare i dati del problema e costruire un modello opportuno (modello è una
3.
rappresentazione della realtà privata degli aspetti superflui alla soluzione del
problema);
descrivere il procedimento risolutivo individuando le operazioni da compiere sui
dati iniziali per ottenere i risultati finali;
21
4. eseguire nell’ordine le operazioni descritte nel processo risolutivo (il risolutore in
questa fase è detto esecutore);
5. verificare se i risultati ottenuti rispondono alle finalità del problema reale
(attendibilità).
Dettagliamo adesso ogni singola fase.
5.1.
Interpretazione (comprensione del problema).
Le semplicità dei problemi (algoritmi) affrontati nei paragrafi precedenti non mettere in risalto
la fase chiamata interpretazione, poiché ci siamo concentrati sull'aspetto risolutivo e non sulla
comprensione del testo del problema. Esempio: calcolo della somma tra due numeri non
richiede alcuna particolare interpretazione. E' chiaro l'obiettico che si vuole raggiungere.
I problemi vengono spesso presentati in modo confuso se non addirittura fuorviante. Purtroppo
però i problemi confusi non sono solo relegati nelle pagine dei libri di enigmi, ma si riscontrano
nella realtà della vita quotidiana dove la loro presenza non sarebbe affatto auspicabile.
Di conseguenza, prima di lanciarsi alla ricerca della soluzione di un problema, è indispensabile
formularne il testo, in modo da:
•
•
•
•
precisare gli obiettivi
evidenziare le regole e i dati impliciti ed espliciti
eliminare ogni tipo di ambiguità
eliminare i dettagli inutili
22
5.2.
Un
modello
Il Modello (modellizzazione della situazione)
è
la
rappresentazione
schematizzata
di
un
problema.
Cioè
sono
delle
semplificazioni della situazione reale, dove vengono messi in evidenza esclusivamente gli
aspetti che si ritengono utili o significativi per la risoluzione e che sono il risultato della fase di
comprensione del problema.
I modelli possono essere diversi:
• modello grafico
• modello verbale
• modello tabellare
• modello simbolico
Spesso il modello di solito è un modello grafico che grazie alla sua potenza espressiva,
consente di rappresentare efficacemente un gran numero di situazioni.
In altre occasioni invece un modello verbale o un modello tabellare risultano più significativi.
In ogni caso il processo di modellizzazione porta sempre ad una astrazione della situazione
reale, cioè una rappresentazione di carattere più generale che potrà essere riutilizzata in
situazioni analoghe.
Dunque un modello è una rappresentazione più semplice di un problema che contiene tutti e
soli gli elementi effettivamente determinanti per la soluzione.
23
5.3.
Procedimento risolutivo
Mentre per la riformulazione del testo del problema è stato possibile fornire una serie di passi
da seguire, la ricerca della soluzione è un'attività logico-intellettuale in cui conoscenze,
intuizioni, tentativi e lavoro metodico si fondono per consentire di definire a priori in che ordine
le varie attività devono essere disposte per facilitare il raggiungimento della meta.
Di conseguenza non è possibile dare una ricetta sicura per risolvere qualsiasi problema
(avremmo risolto tutti i mali del mondo!) , ma solo un elenco di suggerimenti da tener
presente nell'attività risolutiva.
Tuttavia si possono indicare alcune strategie che si possono applicare in molte situazioni.
Le strategie sono:
•
•
•
•
conoscere l'argomento
sfruttare l'esperienza
procedere a ritroso
scomporre i problemi
Conoscere l'argomento
Sicuramente la conoscenza degli argomenti a cui la situazione fa riferimento è una condizione
indispensabile per un coretto approccio alla risoluzione del problema. Per questo quando la
conoscenza degli argomenti è scarsa, occorre procurarsi un minimo di documentazione.
Sfruttare l'esperienza
La ricerca della soluzione sarebbe un'attività lunga e faticosa se ogni problema dovesse essere
affrontato come se fosse un caso isolato. Fortunatamente però i problemi sono spesso
correlabili
tra loro ed è quindi possibile, una volta individuatene la similarità, sfruttare il
procedimento risolutivo di uno di essi per risolvere gli altri.
Nella ricerca della soluzione
ad un nuovo problema sarà dunque possibile sfruttare
l'esperienza e utilizzare condotte risolutive già sperimentate con successo, apportandovi
eventualmente piccole modifiche.
Dunque maggiore è il numero e la tipologia dei problemi risolti e maggiore è l'esperienza
accumulata e di conseguenza maggiore è la capacità di applicare i processi risolutivi a nuove
situazioni.
24
Procedere a ritroso
Viene spontaneo pensare che per scoprire la soluzione di un problema si debba sempre partire
dalle ipotesi contenute nel testo ed avvicinarsi per passi all'obiettivo. Ciò invece non è sempre
vero, poiché esistono casi in cui risulta più produttivo partire dall'obiettivo e procedere a ritroso
fino a pervenire ad un punto in cui tutti i passi necessari divengono noti. A questo punto è
sufficiente ricostruire il percorso all'inverso per esprimere chiaramente il processo risolutivo.
Con questo metodo, detto metodo analitico, si avanza l'ipotesi che ciò che si chiede di
ottenere sia già stato ottenuto e, attraverso un ragionamento regressivo, si risale ai dati
iniziali, definendo di volta in volta i passi necessari per passare da uno stato all'altro.
Scomporre i problemi
Aspettarsi di risolvere i problemi in un colpo solo non è realistico, e per questo nella ricerca
della soluzione conviene articolare un problema in sottoproblemi, in modo tale che, risolvendo
questi ultimi indipendentemente, si possa giungere alla soluzione del problema originale.
Il livello di scomposizione dipende dalla personale interpretazione del concetto di problema
primitivo.
Fig. 2 Tecnica del top-down
Quando dobbiamo trattare un problema di una certa complessità risulta conveniente
suddividere il problema in sottoproblemi di più facile soluzione. Ciò si realizza attraverso
processi di affinamento sempre più dettagliati. Si tratta di scomporre un problema complesso
in sottoproblemi più semplici, utilizzando la tecnica del top-down:




il problema viene esaminato nelle direttrici generali;
scomposto in sottoproblemi;
di ciascun sottoproblema si determinano le operazioni specifiche;
esso viene scomposto in ulteriori sottoproblemi, fino a giungere alle operazioni
elementari.
25
5.4.
Esecuzione
L'omino esecutore
A questo punto, dopo avere definito i formalismi per rappresentare il linguaggio di descrizione
dei processi risolutivi, possiamo presentare un primo modello di sistema di esecuzione
imperativo. Questo modello rappresenta l'ambiente di esecuzione ed è formato da una camera
isolata acusticamente nella quale stanno un omino e alcuni dispositiv:
•
•
•
•
•
•
due finestre, una attraverso la quale entrano dati e istruzioni e l'altra che consente
all'omino di trasmettere all'esterno i risultati dell'elaborazione.
due pulsanti posti al'esterno della camera, collegati all'interno con due luci di diverso
colore, le quali avvertono l'omino che sta per ricevere un nuovo programma, oppure
che deve eseguire l'ultimo programma consegnatogli.
una calcolatrice che permette di eseguire le operazioni aritmetiche di base
una lavagna sul cui angolo superiore sinistro viene fissato il foglio contenente le
istruzioni(programma). Il resto della lavagna viene fissato dall'esecutore per
memorizzare dati e risultati
un blocco note per uso personale
l'occorrente per scrivere e cancellare
Dal punto di vista operativo il nostro omino non prende mai nessuna iniziativa e fa solamente
quello che gli viene comandato, o per iscritto tramite un programma, o attraverso i vari
pulsanti e le relative lampadine; egli inoltre sa compiere solo le seguenti operazioni:
•
•
interpretare il linguaggio formalizzato che abbiamo presentato nei paragrafi precedenti
ed eseguire le operazioni descritte nel programma utilizzando i dispositivi a sua
disposizione
riconoscere, attraverso i codici di luce, i comandi che un utente esterno gli invia.
Esempio. Scrivere un algoritmo che consenta di esaminare un numero imprecisato di terne di
valori numerici e comunichi, di volta in volta, se la terna esaminata può rappresentare i lati di
un triangolo rettangolo.
Per semplicità si suppone che l'utente ogni volta inserisca i tre valori A,B,C in ordine crescente.
L'esecutore dovrà ricevere la terna dall'esterno, verificare se può rappresentare le misure di un
triangolo rettangolo, comunicare il risultato della verifica, ripetere queste operazioni finchè non
sono finite le terne. Pertanto per poter definire la condotta
risolutiva, risulta necessario
affrontare i seguenti problemi:
definire la modalità con cui l'esecutore può verificare se i tre numeri sono le misure dei cateti e
dell'ipotenusa di un triangolo rettangolo(potrebbe non conoscere la geometria)
definire la modalità con cui l'esecutore può capire se le terne da analizzare sono terminate
(l'omino comunica con l'esterno solo con le finestre).
Il primo problema può essere risolto abbastanza facilmente ricordando che per il terema di
Pitagora se i tre valori sono le misure di un triangolo rettangolo vale la relazione a 2+b2=c2 . Di
conseguenza, poiché l'omino non conosce la geometria ma sa effettuare le quattro operazioni
26
ed i confronti tra valori numerici, sarà sufficiente ordinargli di verificare se è valida
l'uguaglianza a2+b2=c2 .
Anche la soluzione al secondo problema è abbastanza semplice. Infatti sarà sufficiente fare in
modo che l'omino, dopo aver comunicato con un opportuno messaggio il risultato del suo
lavoro su una terna, ponga all'utente una domanda del tipo: “Sono finite le terne?” e decida in
base alla risposta se ripetere le operazioni per una nuova terna o terminare l'esecuzione del
programma.
Formalizzando nel linguaggio dell'omino i singoli passi:
Esecutore reale
L'esecutore reale è il calcolatore. Parleremo successivamente e più dettagliatamente di come
funziona l'esecutore reale.
27
5.5.
Verifica dei risultati
La verifica dei risultati discende dal passo precedente. Durante l'esecuzione ed alla fine del
processo risolutivo, occorre verificare che i risultati ottenuti siano quelli attesi. In caso
contrario occorre apportare qualche modifica al procedimento risolutivo evidentemente errato.
Tabelle di traccia
Uso delle tabelle di traccia: prendiamo in esame il flow-chart relativo all'esercizio (scambio dei
valori contenuti in due variabili)
La tabella di traccia si costruisce ponendo sulle colonne le variabili di cui si vuole studiare il
comportamento e sulle righe i valori che assumono tali variabili ogni volta che avanza il
processo. Ad esempio abbiamo supposto che alla partenza x contenga il valore 5 e y il valore
7; la tabella di traccia sarà
Variabile
a
x
y
-
5
7
_____
Inizializzazione
5
5
7
dopo la 1. istruzione
5
7
7
dopo la 2. istruzione
5
7
5
dopo la 3. istruzione
Conviene sempre compilare una tabella di traccia per ogni algoritmo sviluppato (quando ciò è
possibile) in modo da verificare la correttezza della soluzione trovata .
28