Università degli Studi di Cagliari
Corso di Laurea Magistrale in Ingegneria per l’Ambiente ed il Territorio
LABORATORIO
di INFORMATICA
A.A. 2010/2011
Prof. Giorgio Giacinto
CODIFICA DEGLI ALGORITMI
IN UN LINGUAGGIO
DI ALTO LIVELLO
http://www.diee.unica.it/giacinto/Lab
Obiettivi
!
L’obiettivo di questa sezione non è quello di
illustrare tutte le particolarità del linguaggio C
!
In questa sezione si vuole mostrare come,
dato un problema, si possa formulare un
algoritmo che lo risolva.
!
Gli algoritmi verranno espressi usando solo
una piccola parte del linguaggio C
Giorgio Giacinto 2010
Laboratorio di Informatica
2
Introduzione
!
Come abbiamo visto, un linguaggio per la
descrizione di algoritmi deve essere preciso e
sintetico.
!
!
!
La precisione è requisito essenziale per l’esecuzione
automatica
La sinteticità è necessaria per la comprensibilità umana
del programma
Per soddisfare queste due esigenze contrastanti
vengono progettati linguaggi diversi
!
!
per il livello macchina
per il livello uomo (“alto livello”)
Giorgio Giacinto 2010
Laboratorio di Informatica
3
Caratteristiche essenziali di un
linguaggio di alto livello
!
In un linguaggio di alto livello
!
!
!
i riferimenti a elementi del programma come celle di
memoria, istruzioni, costanti, ecc. sono effettuati con
variabili simboliche
le istruzioni e il controllo della sequenza vengono espresse
in un linguaggio molto vicino al linguaggio naturale
(inglese)
Le variabili simboliche prendono il nome di
identificatori: il nome usato per indicarle deve
essere semplice da comprendere.
!
Chi legge un programma scritto da altri deve poter
comprendere quali operazioni vengono compiute e su quali
operandi
Giorgio Giacinto 2010
Laboratorio di Informatica
4
Macchina virtuale che esegue
programmi in linguaggio C
Bus di sistema
x
a
Standard input
alfa
Pippo
Standard output
Unità centrale
Memoria
centrale
Giorgio Giacinto 2010
Laboratorio di Informatica
5
Nucleo del linguaggio C
!
Lo standard input, standard output e la
memoria sono suddivisi in celle elementari.
Ciascuna cella contiene un dato
!
!
!
NOTA: dati diversi (numeri interi, reali, caratteri)
richiedono celle di dimensione diversa
Chiamiamo stringa una successione finita di
caratteri memorizzati in celle consecutive (un
carattere per cella)
Per ora ipotizziamo che la dimensione della
memoria e dei supporti ingresso/uscita sia
illimitata.
Giorgio Giacinto 2010
Laboratorio di Informatica
6
Nucleo del linguaggio C (cont.)
!
Le celle di memoria sono chiamate variabili
!
!
Il contenuto può essere modificato durante l’esecuzione del
programma
Identificatori simbolici: una successione di lettere
e cifre
!
!
Al primo posto sempre una lettera
Distinzione maiuscole e minuscole (Var è diverso da VAR)
Esempi: x, alfa, Giuseppe, DopoDomani,...
Non si può usare lo stesso id. per indicare diversi
elementi né usare diversi id. per lo stesso elemento
Giorgio Giacinto 2010
Laboratorio di Informatica
7
Identificatori riservati (o
predefiniti)
!
Alcune parole sono associate a priori a qualche
elemento del linguaggio
!
!
!
Hanno un significato fissato a priori che non può essere
modificato dal programmatore
Esempio: scanf e printf indicano operazioni elementari
di ingresso/uscita e non possono essere usate per indicare
variabili
Vengono spesso indicate col nome di parole chiave
Negli editor a corredo dei compilatori, spesso le
parole chiave vengono evidenziate con colori diversi
rispetto agli altri elementi di un programma
Giorgio Giacinto 2010
Laboratorio di Informatica
8
Struttura base di un
programma C
main()
{
...
}
!
Intestazione
Qui vengono inserite le istruzioni,
cioè frasi in linguaggio C.
Ciascuna istruzione termina con ;
Il corpo del programma, cioè la sequenza di istruzioni che
realizza una determinata funzione, è racchiuso fra parentesi
graffe
Giorgio Giacinto 2010
Laboratorio di Informatica
9
Istruzioni in linguaggio C
Tre tipi di istruzioni
assegnamento: associare un valore ad una variabile
ingresso e uscita: servono per leggere e scrivere
rispettivamente sui dispositivi di ingresso e uscita
istruzioni composte: gli effetti dell’istruzione
dipendono dalla verità o falsità di una espressione
booleana (o condizione)
Giorgio Giacinto 2010
Laboratorio di Informatica
10
Istruzioni di assegnamento
Sintassi:
<identificatore> = <espressione>
All’identificatore viene associato il valore dell’espressione
<espressione> può essere un valore costante,
espressioni aritmetiche, ecc.
Esempi:
x = 23; w = ‘a’; y = z; alfa = x+y;
r3 = (alfa*43-xgg)*(delta-32*ijj);
Giorgio Giacinto 2010
Laboratorio di Informatica
11
Istruzioni di assegnamento
(cont.)
!
L’esecuzione di una istruzione di assegnamento
comporta la valutazione dell’espressione a destra
del segno =
!
Agli identificatori simbolici vengono sostituiti i valori nelle
celle corrispondenti al momento della valutazione
Esempio:
Se la cella a contiene il valore 45 e z contiene il valore 5,
x = (a–z)/10;
fa sì che nella cella x venga memorizzato il valore 4
Giorgio Giacinto 2010
Laboratorio di Informatica
12
Istruzioni di ingresso e uscita
!
!
scanf() legge dal dispositivo standard di
ingresso (stdin)un valore e lo memorizza
in una variabile
printf() scrive sul dispositivo standard di
uscita (stdout)
!
!
stdin: di solito tastiera
stdout: di solito il monitor
Giorgio Giacinto 2010
Laboratorio di Informatica
13
Struttura dei programmi C
/* Somma sequenze di numeri */
#include <stdio.h>
Direttive al pre-processore C
main()
{
Dichiarazioni di costanti e di
int numero, somma;
variabili
somma = 0;
scanf(“%d”,&numero);
while(numero!=0)
{
somma = somma+ numero;
Istruzioni di I/O
scanf(“%d”,&numero);
}
printf(“La somma è: %d\n”,somma);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
14
La parte dichiarativa dei
programmi
!
Il linguaggio C chiede che tutte gli
identificatori usati all’interno del programma
vengano dichiarati
!
!
!
Facilita l’individuazione di errori (ad esempio si
scrive alba anziché alfa, dove alfa è stata
dichiarata, mentre alba no)
Notifica al C che tipo di valori dovrà memorizzare
(caratteri, numeri interi, numeri in virgola mobile,
ecc.)
La parte dichiarativa precede la parte
esecutiva che contiene le istruzioni.
Giorgio Giacinto 2010
Laboratorio di Informatica
15
Dichiarazione di variabili
!
Sintassi
<identificatore_di_tipo> <lista_dichiarazione>
<identificatore_di_tipo>::=int | float | char…
<lista_dichiarazioni>::= <dichiarazione>[{,<dichiarazione>}];
<dichiarazione>::=
<identificatore> | <identificatore> = <valore_iniziale>
tipo: l’insieme dei valori che la variabile può assumere
int: interi; float: virgola mobile; char: carattere, ecc.
Giorgio Giacinto 2010
Laboratorio di Informatica
16
Dichiarazione di variabili
(cont.)
float
int
char
x,y;
i,j;
simb;
Significato:
Nel programma si useranno le variabili x e y come numeri in virgola
mobile, i e j come interi e simb come carattere
Ne consegue che, ad es., j non potrà mai assumere il valore 3.14
(qual è il risultato di j=3.14;?)
Giorgio Giacinto 2010
Laboratorio di Informatica
17
Dichiarazione di costanti
Sintassi
const <identificatore_di_tipo> <lista_dichiarazione>
<identificatore_di_tipo>::=int | float | char…
<lista_dichiarazioni>::= <dichiarazione>[{,<dichiarazione>}];
<dichiarazione>::= <identificatore> = <valore_iniziale>
Una dichiarazione di costante associa in maniera permanente
un valore ad un identificatore per la durata dell’esecuzione del
programma
Giorgio Giacinto 2010
Laboratorio di Informatica
18
Dichiarazione di costanti
(cont.)
const
const
const
const
float
float
int
char
PiGreco = 3.14;
PiGreco = 3.1415, e = 2.718;
N = 100, M = 1000;
Car1 = ‘G’, Car2 = ‘R’;
La definizione di costanti è utile
!
!
Per utilizzare un identificatore simbolico nel corpo del
programma (ad es. PiGreco al posto di 3.14) che ne
migliora la comprensibilità
Per poter parametrizzare il programma. Se si
desidera cambiare il valore di una costante non è
necessario rintracciarne tutte le occorrenze nel
programma, ma è sufficiente modificare la
dichiarazione iniziale.
Giorgio Giacinto 2010
Laboratorio di Informatica
19
Sintassi di scanf
scanf(stringa_di_controllo, elementi_da_leggere);
!
La stringa_di_controllo contiene una lista di caratteri di
conversione o di formato preceduti dal simbolo % (la lista è
racchiusa fra “ “)
In questo modo di specifica il formato con cui devono essere
interpretati i caratteri letti da tastiera
!
!
!
!
!
%d per leggere un intero
%c per leggere un carattere
%f per leggere un numero reale (floating point)
%s per leggere una stringa di caratteri
La lista di elementi_da_leggere contiene i nomi preceduti da &
delle variabili in cui devono essere memorizzati i dati letti da
tastiera (gli elementi sono separati da virgole).
Le variabili sono nello stesso ordine degli elementi da leggere
specificati dalla stringa_di_controllo.
Giorgio Giacinto 2010
Laboratorio di Informatica
20
Esempio di utilizzo di scanf
scanf(“%c%c%c%d%f”,&c1,&c2,&c3,&i,&x);
Se al momento dell’esecuzione l’utente inserisce
ABC 3 7.345
c1 conterrà A (c1 deve essere definita di tipo char)
c2 conterrà B (c2 deve essere definita di tipo char)
c3 conterrà C (c3 deve essere definita di tipo char)
i conterrà 3 (i deve essere definita di tipo int)
x conterrà 7.345 (x deve essere definita di tipo float)
Giorgio Giacinto 2010
Laboratorio di Informatica
21
Sintassi di printf
!
!
E’ la funzione che consente di generare un output
formattato sul dispositivo di uscita standard
printf(stringa_di_controllo, elementi_da_stampare)
!
La stringa_di_controllo è una stringa (racchiusa fra “ ”)
che viene stampata in uscita e che può contenere caratteri
di conversione o di formato preceduti dal simbolo % e
altri simboli (ad es., \n provoca un salto a nuova riga)
! %d per stampare un intero
! %c per stampare un carattere
! %f per stampare un numero reale (floating point)
! %s per stampare una stringa di caratteri
Giorgio Giacinto 2010
Laboratorio di Informatica
22
Sintassi di printf (cont.)
!
printf(stringa_di_controllo, elementi_da_stampare)
!
!
Gli elementi_da_stampare sono costituiti da una lista di
! variabili, costanti, espressioni (gli elementi sono separati da
virgola),
nello stesso ordine in cui compaiono i corrispondenti
caratteri di conversione nella stringa_di_controllo.
I caratteri preceduti da % vengono detti di conversione
perché devono convertire il contenuto delle variabili,
costanti ecc. in caratteri stampabili
Giorgio Giacinto 2010
Laboratorio di Informatica
23
Esempio di utilizzo di printf
printf(“Lo stipendio annuo dei dipendenti di categoria %d
è pari a %f Euro\n”,cat,stip);
dove cat è definita come variabile intera (int) e stip come variabile reale
(float).
Se cat contiene il valore 6 e stip il valore 1570.58, l’istruzione stampa la
stringa seguente
Lo stipendio annuo dei dipendenti di categoria 6 è pari a
1570.5 Euro
e il cursore viene spostato sulla riga seguente
Giorgio Giacinto 2010
Laboratorio di Informatica
24
Esempio di utilizzo di printf
(cont.)
printf(%s\n%c%c\n\n%s\n,“Questo programma è stato scritto
da”,iniz-nome,iniz-cognome,”Buon lavoro!”);
Se iniz-nome e iniz-cognome sono definite come variabile carattere
(char) e contengono rispettivamente M e P
l’istruzione stampa la stringa seguente:
Questo programma è stato scritto da
MP
Buon lavoro!
e il cursore viene spostato sulla riga seguente
Giorgio Giacinto 2010
Laboratorio di Informatica
25
Il preprocessore C
!
!
!
Costituisce la prima fase della compilazione di un
programma in linguaggio C
La direttiva #include viene usata per includere nel
programma corrente il contenuto del file specificato.
La direttiva #define viene usata per sostituire ad un
identificatore una stringa arbitraria di caratteri
!
Ad es. #define DIMENSIONE 100 ad ogni occorrenza di
DIMENSIONE il preprocessore sostituisce il valore 100
! A differenza di una costante, non è una variabile in
memoria, ma la sostituzione viene effettuata dal
compilatore prima della compilazione vera e propria
Giorgio Giacinto 2010
Laboratorio di Informatica
26
#include
!
E’ comodo disporre di un certo insieme di
funzioni e definizioni di libreria.
!
!
Sono funzioni e definizioni che estendono le
funzionalità di base del linguaggio C
Le funzioni di libreria possono essere definite
dall’utente oppure appartenere a un insieme
definito dallo standard ANSI C
!
Le funzioni della libreria standard sono
disponibili in qualunque ambiente di
programmazione e hanno sempre la stessa
sintassi
Giorgio Giacinto 2010
Laboratorio di Informatica
27
#include <stdio.h>
!
!
!
Il linguaggio C in senso stretto non possiede
istruzioni per realizzare I/O
In ciascun ambiente di programmazione sono
sempre disponibili le funzioni scanf e printf
Le funzioni per l’I/O sono sempre definite nel file
stdio.h
!
#include <stdio.h> produce come effetto l’inclusione nel
programma corrente del file stdio.h. ed è necessario per
usare le funzioni di I/O (come ad es. printf e scanf)
Le parentesi angolate <> indicano che il file si trova nella
directory predefinita dal compilatore che contiene le libreria
standard.
Giorgio Giacinto 2010
Laboratorio di Informatica
28
Istruzioni composte
!
Sono costruite componendo istruzioni più
semplici
!
Questa caratteristica non è posseduta dalla
macchina di Von Neumann
!
La costruzioni di istruzioni composte non ha
limiti: ogni istruzione composta può
contenere al suo interno istruzioni composte
Giorgio Giacinto 2010
Laboratorio di Informatica
29
Istruzioni composte (cont.)
!
Sono istruzioni che producono effetti diversi a
seconda che siano verificate o meno certe
condizioni sul valore delle variabili
!
Le condizioni sono espressioni booleane il
cui valore può essere solo vero o falso
!
Le condizioni sono costruite mediante
operatori relazionali e operatori logici
Giorgio Giacinto 2010
Laboratorio di Informatica
30
Operatori relazionali e logici
Operatori relazionali
==
!=
<
>
<=
>=
uguale
diverso
minore
maggiore
minore o uguale
maggiore o uguale
Giorgio Giacinto 2010
Operatori logici
&&
||
!
AND
OR
NOT
N.B. nel linguaggio C il valore
logico vero corrisponde a
qualunque valore diverso da
0 mentre falso corrisponde al
valore 0
Laboratorio di Informatica
31
Esempi espressioni
condizionali
x == 0
(vero se il valore memorizzato in x è 0)
alfa > beta && x != 3
(vero se il valore memorizzato in alfa è maggiore del valore
memorizzato in beta e se contemporaneamente il valore memorizzato
in x è diverso da 3)
!((a + b) * 3 > x || a < c)
Si valutano le espressioni (a + b) * 3 > x e a < c. Se
almeno una delle due è vera, o se sono entrambe vere (OR logico)
allora il risultato è falso (tutta l’espressioni è negata)
Giorgio Giacinto 2010
Laboratorio di Informatica
32
Precedenza operatori
Giorgio Giacinto 2010
Laboratorio di Informatica
33
Istruzione condizionale
Sintassi:
<istruzione condizionale>::=
if(<espressione condizionale>) <sequenza istruzioni>
[else <sequenza istruzioni>]
<sequenza istruzioni>::=<istruzione>|{{<istruzione>}2+}
! Se l’espressione condizionale è vera, viene eseguita
la sequenza di istruzioni che segue if()
! E’ opzionale inserire una sequenza di istruzioni da
eseguire se l’espressione condizionale è falsa
Giorgio Giacinto 2010
Laboratorio di Informatica
34
Esempi istruzione
condizionale
if(x == 0) z = 5; else y = z + w*y;
se x vale 0, allora assegna 5 a z altrimenti assegna a y il valore di z+w*y
if((x+y)*(z-2)>(23+v)) {z=x+1; y=13+x;}
if((x==y && z>3) || w!=y) z=5;
else{y=z+w*y; x=z;}
Le espressioni seguenti sono scorrette (perché?)
if(x==0) else y=z; y=34;
if(x==0) a; else b+c;
Giorgio Giacinto 2010
Laboratorio di Informatica
35
Istruzione iterativa (ciclo o
loop)
Sintassi:
<istruzione iterativa>::=
while(<espressione condizionale>) <sequenza istruzioni>
<sequenza istruzioni>::=<istruzione>|{{<istruzione>}2+}
! Si esegue ripetutamente la sequenza di istruzioni
fintantoché l’espressione condizionale è vera
!
Si valuta l’espressione condizionale. Se è falsa, il
programma prosegue senza eseguire la sequenza di
istruzioni. Se è vera, si esegue la sequenza di
istruzioni e poi si prosegue ciclicamente valutando la
condizione. Il ciclo termina quando la condizione è
falsa.
Giorgio Giacinto 2010
Laboratorio di Informatica
36
Esempi di istruzioni iterative
while(x >= 0) x = x-1;
decrementa x fino a che x è maggiore o uguale a 0. Il ciclo termina
quando x assume il valore –1
while(z != y) {y = z-x; x = x*3;}
In dipendenza dai valori iniziali di x, y e z questo ciclo potrebbe
essere infinito
Giorgio Giacinto 2010
Laboratorio di Informatica
37
Primi esempi
di programmi in C
!
Vedremo esempi di complessità via via cresecente
!
Per aiutare la lettura e la comprensione di un
programma
!
!
Lettura: le istruzioni vengono indentate. La sequenza di
istruzioni che dipende da espressioni condizionali viene
scritta con un rientro a destra rispetto all’allineamento della
istruzione condizionale
Comprensione: inserimento di commenti in linguaggio
naturale. I commenti sono compresi fra i simboli /* e */ e
sono ignorati dal compilatore
Giorgio Giacinto 2010
Laboratorio di Informatica
38
Avvertenze sui primi esempi di
programmi in C
!
Scopo di questi esempi è illustrare il flusso
delle operazioni da eseguire
!
!
La sintassi completa del C non è usata per
maggiore chiarezza
Per compilare ed eseguire i programmi
seguenti occorre completarne la scrittura
!
!
!
inclusione della libreria stdio.h
dichiarazione delle variabili usate
completamento istruzioni I/O
Giorgio Giacinto 2010
Laboratorio di Informatica
39
(1) Lettura di due numeri da
stdin e stampa del maggiore
/*Prima versione*/
main()
{
scanf(x);
scanf(y);
if(x>y) z=x;
else z=y;
printf(z);
}
Giorgio Giacinto 2010
/*Seconda versione*/
main()
{
scanf(x);
scanf(y);
if(x>y) printf(x);
else printf(y);
}
Laboratorio di Informatica
40
(2) Lettura sequenza numeri e
ricerca del primo 0
main()
{
uno=1;
scanf(dato);
while(dato) scanf(dato);
printf(uno);
}
N.B. L’espressione del while equivale a dato!=0
Giorgio Giacinto 2010
Laboratorio di Informatica
41
(3) Somma di una sequenza di
numeri
Ipotesi: la cifra ‘0’ indica la fine della sequenza
main()
{
somma=0;
scanf(numero);
while(numero)
{
somma = somma + numero;
scanf(numero);
}
printf(somma);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
42
(4) Gioco “carta, forbici, sasso”
!
Il programma deve realizzare il gioco seguente fra
due giocatori
!
!
!
Il programma legge da stdin due caratteri che
rappresentano gli oggetti scelti dai due giocatori
!
!
Ogni giocatore sceglie un oggetto fra carta, forbici e sasso
I due oggetti vengono confrontati secono la logica:
! la carta prevale sul sasso
! le forbici prevale sulla carta
! il sasso prevale sulle forbici
‘c’=carta, ‘f’=forbici, ‘s’=sasso
Il programma scrive su stdout il vincitore o il
risultato pari nel caso di scelta dello stesso colore
Giorgio Giacinto 2010
Laboratorio di Informatica
43
(4) Gioco “carta, forbici, sasso”
main()
{
scanf(PrimoOggetto);
scanf(SecondoOggetto);
if(PrimoOggetto == SecondoOggetto)
printf(“Il gioco è pari”);
else
if((PrimoOggetto ==‘c’&& SecondoOggetto ==‘s’) ||
(PrimoOggetto ==‘f’&& SecondoOggetto ==‘c’) ||
(PrimoOggetto ==‘s’&& SecondoOggetto ==‘f’))
printf(“Il vincitore è il giocatore n. 1”);
else
printf(“Il vincitore è il giocatore n. 2”);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
44
(4) Gioco “carta, forbici, sasso”
osservazioni
!
Abbiamo usato istruzioni composte annidate
!
!
!
Il primo if stabilisce se c’è un vincitore o no
Se c’è un vincitore, bisogna stabilire chi è (secondo if)
Se in una serie di if annidati, qualcuno è seguito da
else e qualcuno no, come si interpreta?
il C usa la convenzione di associare l’else all’if più vicino
Ad esempio: if(C1) if(C2) S1; else S2;
l’else è l’alternativa a if(C2)
Se invece l’else deve essere l’alternativa a if(C1)
if(C1) {if(C2) S1;} else S2;
!
Giorgio Giacinto 2010
Laboratorio di Informatica
45
(5) Triangoli
Problema:
Dati tre numeri in ingresso, stabilire se si può trattare
delle lunghezze dei tre lati di un triangolo
Proprietà dei lati di un triangolo:
ciascun lato ha lunghezza inferiore della somma degli altri due
Se si tratta delle lunghezze dei tre lati di un triangolo,
determinare se è scaleno, isoscele o equilatero.
Giorgio Giacinto 2010
Laboratorio di Informatica
46
(5) Triangoli - listato C
main()
{
scanf(X); scanf(Y); scanf(Z);
if((X<Y+Z)&&(Y<X+Z)&&(Z<X+Y))
if(X == Y && Y == Z)
printf(“I dati letti corrispondono a un triangolo
equilatero”);
else
if(X == Y || Y == Z || X == Z)
printf(“I dati letti corrispondono a un triangolo
isoscele”);
else
printf(“I dati letti corrispondono a un triangolo
scaleno”);
else
printf(“I dati letti non corrispondono a nessun
triangolo”);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
47
(5) Triangoli - osservazioni
!
!
Per determinare il tipo di triangolo potevano essere
scelte altre strade (ad es. prima la verifica se
isoscele o equilatero, altrimenti scaleno)
Nota sulle espressioni condizionali:
In analisi matematica a==b==c oppure a<b<c
sono espressioni lecite, MA NON IN C
a==b==c verrebbe eseguita da sn verso dx.
a==b restituisce un valore booleano (attenzione! In C
falso è rappresentato dallo 0, vero da valori diversi da
0)… e non ha senso confrontarlo con c!
Giorgio Giacinto 2010
Laboratorio di Informatica
48
(6) Massimo comun divisore
Primo algoritmo
Dati due numeri interi positivi m e n:
! fai
la scansione di tutti i numeri compresi fra 1 e il
minimo fra m e n
! Per ciascuno di essi stabilisci se è un divisore
comune fra m e n (la divisione deve dare resto 0)
! Se sì, memorizza come MCD attuale
! Considera l’intero successivo.
! Alla fine, la variabile usata per memorizzare il
MCD temporaneo conterrà il MCD fra i due numeri
Giorgio Giacinto 2010
Laboratorio di Informatica
49
(6) Massimo comun divisore
Primo algoritmo - listato C
main()
{
scanf(n); scanf(m);
MCD = 1;
if(n <= m) min = n; else min = m;
contatore = 1;
while (contatore <= min)
{
if(n % contatore == 0 && m % contatore == 0)
MCD = contatore;
contatore = contatore + 1;
}
printf(MCD);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
50
(6) Massimo comun divisore
Algoritmo di Euclide
Se m = n allora MCD(m,n) = m = n
! Se m ! n (ad es. m > n) allora MCD(m,n) = MCD(m-n,n)
Infatti se k è un divisore comune a m e a n,
! m = k!d e n = k!r
! m - n = k ! (d - r)
! d – r è un intero positivo
! Simmetricamente se k è un divisore comune a m-n e n,
allora lo è anche per m e n
! Si ottiene una catena di uguaglianze fra MCD che termina
quando m e n sono uguali (vedi prima riga), magari uguali al
valore 1.
!
Giorgio Giacinto 2010
Laboratorio di Informatica
51
(6) Massimo comun divisore
Algoritmo di Euclide - listato C
main()
{
scanf(n); scanf(m);
while(m != n)
if(m > n)
m = m – n;
else /* sicuramente n > m perché il ciclo
è per m != n
*/
n = n - m;
MCD = n;
printf(MCD);
}
Giorgio Giacinto 2010
Laboratorio di Informatica
52
(6) Massimo comun divisore
commenti sui due algoritmi
!
Il secondo algoritmo è più elegante (è vicino
a una formulazione ricorsiva. Qual è?)
!
Il primo algoritmo è più efficiente se la
differenza fra i due numeri è grande,
altrimenti è più efficiente il secondo
!
Il numero di calcoli da effettuare nel primo
algoritmo dipende dalla dimensione del numero
più piccolo, mentre nel secondo dipende dalla
differenza dei due numeri.
Giorgio Giacinto 2010
Laboratorio di Informatica
53
Costruzione incrementale di
programmi
!
!
La soluzione di problemi complessi richiede spesso
la costruzione di algoritmi complessi
Una tecnica per progettare algoritmi complessi
consiste nell’affrontare il problema a diversi livelli
di dettaglio
!
!
Inizialmente si producono formulazione compatte
! Ad esempio, se è necessario effettuare un ordinamento,
non si precisa l’algoritmo di ordinamento
Le formulazioni compatte di un algoritmo sono spesso
espresse usando uno pseudocodice, cioè un ibrido fra un
linguaggio di programmazione e il linguaggio naturale
Giorgio Giacinto 2010
Laboratorio di Informatica
54