Esercizio - Università degli Studi di Roma "Tor Vergata"

Fondamenti di Informatica - 1
Prof. B.Buttarazzi
A.A. 2011/2012
Sommario
• Operatore ?
• Tipo di dato: struct
• La ricorsione
– Funzioni ricorsive
• Esercizi proposti
26/04/2012
2
Operatore ?
L'operatore ? può essere utilizzato per scrivere un'istruzione condizionale del tipo
if-else in modo più rapido.
Sintassi:
espressione_test ? azione_true : azione_false;
Esempio:
(var1>var2)?x=0:x=1
Si valuta l’espressione l’espressione_test (ovvero (var1>var2) )
se è vera si esegue azione_true (cioè x=0;), altrimenti si esegue azione_false
(cioè x=1;)
Equivale all'istruzione
if (var1>var2) x=0
else x=1;
L'operatore ? viene anche denominato operatore ternario in quanto richiede tre operandi.
3
Operatore ?
Esempio completo
#include <iostream>
using namespace std;
int main()
{ int m, n;
cout << "Digita Y o N> ";
char c;
cin >> c;
cout << (
(( c == 'Y')|| ( c == 'y'))
? "Hai accettato!"
: "Non accettato o non valido"
)<< endl;
return 0; }
4
Operatore ?
Esempi:
cout << "\nDigita valore ";
int valore;
cin >> valore;
bool positivo=false;
positivo =( (valore>=0) ? true : false);
cout << "\nvalore= "<<valore<<" "<<positivo<<endl;
cout << "\nDigita importo ";
int aliquota,importo;
cin >> importo;
aliquota = ((importo>=60000) ? 45 : 33);
cout << "\nimporto = "<<importo<<" aliquota = "<<aliquota;;
5
Struct
Il tipo struct ( record ) è tipo di dato che permette di rappresentare in modo
aggregato (sotto uno stesso nome) gruppi di valori non omogenei (ossia tipi di dato
differenti) come ad esempio dati numerici (es. numero telefonico, voto, ecc.) e
testuali (nome, cognome, ecc.)
Un tipo struct (redocrd) è costituito da un elenco di campi, ognuno dei quali sarà
accessibile singolarmente.
I campi possono a loro volta essere delle strutture.
struct studente{
int matricola;
string materia;
int g,m,a;
int voto;
};
struct contatto {
int id;
string nome;
int telefono;
string indirizzo;
};
6
Struct
Una struct si dichiara con la seguente sintassi:
struct NomeStruttura {
tipo_elemento1
nome_elemento1;
tipo_elemento2
nome_elemento2;
...
};
In questo modo noi abbiamo definito solo un tipo di struttura, ma non abbiamo ancora creato
nessuna variabile. Per creare variabili di tipo struct si può procedere in 3 modi:
Prima modalità (elencando le variabili da dichiarare separate da virgola dopo le
parentesi graffe della dichiarazione della struttura)
struct contatto {
int id;
string nome;
int telefono;
string indirizzo; } contatto1, contatto2;
7
Struct
Seconda modalità (dichiarando le variabili di tipo struct come delle normali variabili
ovvero facendo precedere al nome della variabile il tipo "NomeStruttura“
precedentemente dichiarato.)
struct contatto {
int id;
string nome;
int telefono;
string indirizzo; };
contatto contatto1, contatto2;
Terza modalità (inizializzando un variabile struttura in fase di dichiarazione, facendo
seguire al nome della variabile un uguale e i dati da mettere nei campi della struttura
contenuti tra parentesi graffe e separati da virgola)
contatto contatto1 = {0, "Rossi Mario", 03928723, "via XX settembre, 1"};
8
Trattamento dei campi di un record (struct)
Data la struct stud
e una variabile studente di tipo
stud
L’input e l’output della
struct ( record ) avviene un
campo alla volta
struct stud
{
string cognome;
string nome;
int annoNascita;
};
stud studente;
Esempio:
La visualizzazione del
cout<<“\ncognome = “<<studente.cognome;
record prevede l’output dei
cout<<“\nnome = “<<studente.nome;
singoli campi
cout<<“\nanno di nascita = “<<studente.annoNascita;
Struct
Ogni campo di una struct può essere considerato come una variabile singola con il
nome seguente:
Nome_Variabile.Nome_Campo
Es.
contatto1.nome
contatto2.indirizzo
Possiamo creare array di struct .
Ad esempio, utilizzando la struct contatto (definita prima) creare una rubrica di
contatti
contatto rubrica[100];
In questo modo abbiamo creato una rubrica di 100 contatti, e se ad esempio vogliamo
stampare il nome del primo contatto dobbiamo scrivere:
cout<<rubrica[0].nome
10
Esercizio
Definire una struttura adatta a memorizzare i dati di un libro( titolo del
libro, costo, numero di pagine) successivamente si scriva un programma
che acquisisce due libri e stampa ti dati del libro che costa di più
Esercizio
Definire una struttura adatta a memorizzare i dati di un libro( titolo del
libro, costo, numero di pagine) successivamente si scriva un programma
che acquisisce due libri e stampa ti dati del libro che costa di più
struct libro
{ string titolo;
float prezzo;
int numeroPagine;
};
#include <iostream>
#include <string>
using namespace std;
struct libro
{ string titolo;
float prezzo;
int numeroPagine;
};
Esercizio
Definire una struttura adatta a memorizzare i dati di un libro( titolo del
int main()
libro,
costo, numero di pagine) successivamente si scriva un programma
{
L1, L2;
che libro
acquisisce
due libri e stampa ti dati del libro che costa di più
cout<<"\nindica i dati del primo libro:"<<endl;
cout<<"\ntitolo : "; cin>>L1.titolo;
cout<<"\nprezzo : "; cin>>L1.prezzo;
cout<<"\npagine : "; cin>>L1.numeroPagine;
cout<<"\nindica i dati del secondo libro:"<<endl;
cout<<"\ntitolo : "; cin>>L2.titolo;
cout<<"\nprezzo : "; cin>>L2.prezzo;
cout<<"\npagine : "; cin>>L2.numeroPagine;
struct libro
{ string titolo;
float prezzo;
int numeroPagine;
};
if(L1.prezzo>L2.prezzo)
{ cout<<"\nIl libro piu' costo e' "<<L1.titolo;
cout<<" con prezzo "<<L1.prezzo;
cout<<" e pagine "<<L1.numeroPagine<<endl;
}
else
{ cout<<"\nIl libro piu' costo e' "<<L2.titolo;
cout<<" con prezzo "<<L2.prezzo;
cout<<" e pagine "<<L2.numeroPagine<<endl;
}
return 0;
}
Esercizio
Definire una struttura adatta a memorizzare i dati di uno studente e
successivamente scrivere un programma C++ che permetta di inserire
da input i dati degli allievi di un corso e di stampare le matricole degli
allievi che hanno il campo voto > di 24.
Esercizio
Definire una struttura adatta a memorizzare i dati di uno studente e
successivamente scrivere un programma C++ che permetta di inserire
da input i dati degli allievi di un corso e di stampare le matricole degli
degli allievi che hanno il campo voto > di 24.
struct studente{
string nome;
int matricola;
string materia;
int g,m,a;
int voto;
};
const int n=10;
studente allievi[n]; //array di tipo studente
La ricorsione
In C++ ogni funzione può chiamare anche se stessa, secondo
una tecnica detta ricorsione.
Ovviamente tali funzioni devono sempre contenere
un’istruzione di controllo che ha il compito di interrompere la
successione delle chiamate, se si verificano certe condizioni.
16
Il calcolo del fattoriale
La funzione fattoriale, molto usata nel calcolo
combinatorio, è così definita
n!
1
se n 0
n(n 1)! se n 0
dove n è un numero intero non negativo
17
Confronto fra definizione iterativa e ricorsiva
Funzione non ricorsiva
Funzione ricorsiva
n!= 1*2*3*...*(n-1)*n
0!=1
n!= n*(n-1)!;
fatt(n)= 1*2*3*...*(n-1)*n;
fatt(n)=n*fatt(n-1)
18
Il calcolo del fattoriale
• Vediamo di chiarirne il significato
0! = 1
1! = 1(1-1)! = 1·0! = 1·1 = 1
2! = 2(2-1)! = 2·1! = 2·1 = 2
3! = 3(3-1)! = 3·2! = 3·2·1 = 6
4! = 4(4-1)! = 4·3! = 4·3·2·1 = 24
5! = 5(5-1)! = 5·4! = 5·4·3·2·1 = 120
• Quindi, per ogni n intero positivo, il fattoriale di n
è il prodotto dei primi n numeri interi positivi
Il calcolo del fattoriale
Per implementare la funzione per il calcolo del fattoriale in modo
iterativo siamo costretti a fare un’analisi della definizione per scrivere
l’algoritmo
#include <iostream>
using namespace std;
int fatt(int);
int main()
{
int n;
do {
cout << "\nIntroduci un numero >0 : ";
cin >> n;}
while (n<=0);
cout << "Fattoriale di: " << n<< " =" << fatt(n) << endl;
return 0; }
20
Il calcolo del fattoriale
Per implementare la funzione per il calcolo del fattoriale in modo
iterativo siamo costretti a fare un’analisi della definizione per scrivere
l’algoritmo
#include <iostream>
usingsenza
namespace
usarestd;
la ricorsione
int fatt(int);
int main()
{ int fatt(int k)
int n;{ int i = 2,m =1;
do {while ( i <= k )
cout <<
un numero
{ "\nIntroduci
m *= i++
; } >0 : ";
cin >> n;}
return m;
while (n<=0);
} "Fattoriale di: " << n<< " =" << fatt(n) << endl;
cout <<
return 0; }
21
Il calcolo del fattoriale
• Implementando direttamente la definizione
ricorsiva, è naturale scrivere:
int fatt (int k)
{ if (k==0)return 1;/*istruzione di controllo */
else return k*fatt(k-1);}
Il calcolo del fattoriale
#include <iostream>
using namespace std;
int fatt(int);
int main()
{
int n;
do {
cout << "\nIntroduci un numero >0 : ";
cin >> n;}
while (n<=0);
cout << "Fattoriale di: " << n<< " =" << fatt(n) << endl;
return 0; }
int fatt (int k)
{ if (k==0)return 1;/*istruzione di controllo */
else return k*fatt(k-1);}
23
Il calcolo del fattoriale
La funzione ricorsiva fattoriale non necessita di iterazioni, ma include internamente il
calcolo del risultato, infatti restituisce 1 se il parametro ricevuto è uguale a 0 mentre in
caso contrario il valore restituito è il prodotto di n per il fattoriale (n-1), pertanto
fattoriale calcola il valore da restituire chiamando se stessa e "passandosi" come
parametro il parametro appena ricevuto, diminuito di uno.
int fatt (int k)
{ if (k==0)return 1;/*istruzione di controllo */
else return k*fatt(k-1);}
Questa soluzione si basa sulla invocazione di una funzione mentre si esegue
la funzione stessa!
Questa possibilità è permessa in tutti i linguaggi di programmazione che
ammettono la ricorsione
La ricorsione
Per capire come utilizzare correttamente la ricorsione,
vediamo innanzitutto come funziona.
Quando una funzione ricorsiva invoca se stessa, vengono
eseguite le stesse azioni di quando viene invocata una
funzione qualsiasi
– Si sospende l’esecuzione della funzione chiamante (le
variabili locali rimangono congelate)
– Si esegue la funzione chiamato fino alla sua terminazione (con
nuove variabili locali e passando i parametri per valore)
– Si riprende l’esecuzione della funzione chiamante dal punto
in cui era stata sospesa (recuperando le variabili locali)
25
La ricorsione
• Vediamo la sequenza delle istruzioni per calcolare 3!
si chiama f(3)
f(3) lascia in sospeso il calcolo 3* f(2) e chiama f(2)
f(2) lascia in sospeso il calcolo 2* f(1) chiama f(1)
f(1) lascia in sospeso il calcolo 1* f(0) e chiama f(0)
f(0) restituisce 1 a f(1)
f(1) calcola1*1 e restituisce 1 a f(2)
f(2) calcola 2*1 e restituisce 2 a f(3)
f(3) calcola 3*2 e restituisce 6 alla funzione chiamante
• Si crea quindi una pila ( stack) di funzioni “in attesa”,
ciascuno con le sue variabili locali, che si allunga e che poi
si accorcia fino ad esaurirsi
La ricorsione
• Chiamare una funzione mentre si esegue la stessa funzione
è un paradigma di programmazione che si chiama
ricorsione
e una funzione che ne faccia uso si chiama
Funzione ricorsiva
• La ricorsione è uno strumento molto potente per realizzare
alcuni algoritmi (ma è anche fonte di errori di difficile
diagnosi)
• Esistono infatti due regole ben definite (passo base e passo
ricorsivo) che vanno utilizzate per scrivere funzioni ricorsive
che funzionino.
27
Prima regola
La ricorsione: passo base
– la funzione ricorsiva deve fornire la soluzione del
problema in almeno un caso particolare, senza
ricorrere ad una chiamata ricorsiva
– questo caso si chiama caso base della ricorsione
– nel nostro esempio, il caso base era
if (n == 0)
return 1;
– a volte ci sono più casi base, infatti non è necessario
che il caso base sia unico
28
Seconda regola
La ricorsione: passo ricorsivo
– la funzione ricorsiva deve effettuare la chiamata
ricorsiva dopo aver semplificato il problema
– nel nostro esempio, per il calcolo del fattoriale di n si
invoca la funzione ricorsivamente per conoscere il
fattoriale di n-1, cioè per risolvere un problema più
semplice
f = n * fattoriale(n - 1);
– il concetto di “problema più semplice” varia di volta in
volta: in generale, bisogna avvicinarsi ad un caso base
29
Ricorsione infinita
• Si noti quindi che non tutte le funzioni ricorsive
realizzano algoritmi!
– se manca il caso base, la funzione ricorsiva continua ad
invocare se stessa all’infinito
– se il problema non viene semplificato ad ogni
invocazione ricorsiva, la funzione ricorsiva continua ad
invocare se stessa all’infinito
• In questo caso la lista delle funzioni “in attesa” si
allunga indefinitamente, l’ambiente runtime
esaurisce la memoria disponibile per tenere traccia
di questa lista, e il programma termina con un
errore.
30
Ricorsione infinita
Le regole appena viste
• implicano che ad ogni invocazione il problema diventi più
semplice avvicinandosi sempre più al caso base che non
richiede ricorsione
• ovvero che per quanto complesso possa essere il problema
la soluzione sia calcolata in un numero finito di passi
31
Esercizio
Scrivere una funzione ricorsiva e una iterativa che
ricevendo in input, come parametro un intero n,
calcola F(n) dove F è la funzione di Fibonacci.
Esercizio
• Scrivere una funzione ricorsiva per il
calcolo della funzione esponenziale definita
come segue:
26/04/2012
33
Esercizio
Scrivere un programma che calcola il prodotto
tra due numeri interi a e b mediante una
funzione ricorsiva che utilizza somme
successive.
Suggerimento
Il calcolo da svolgere deve essere del tipo
a*b = a*(b-1)+a;
34
Esercizio
Scrivere una funzione che, dati come
parametri di input un array di interi a ed un
intero n, restituisce il numero delle occorrenze
di n in a.
35
Esercizio
Scrivere una funzione che, dati come
parametri di input un array di interi a ed un
intero n, restituisce la posizione della prima
occorrenza di n in a, e -1 se n non compare in
a.
36
Esercizio
Scrivere una funzione che, dati come
parametri di input un array di interi a ed un
intero n, restituisce true se n compare in a,
false altrimenti.
37
Esercizio
Scrivere una funzione che, dati come
parametri di input un array bidimensionale di
interi a ed un intero n, restituisce true se n
compare in a, false altrimenti.
26/04/2012
38
Esercizio
Scrivere una funzione che dati come parametri
di input un array di interi restituisca true se
tutti i suoi elementi sono identici, e false
altrimenti.
26/04/2012
39
Esercizio
Scrivere una funzione che, dati come
parametri di input un array bidimensionale di
interi a e due interi k ed n, restituisce true se
in ogni riga a[i] di a esistono almeno k
elementi maggiori di n, altrimenti la funzione
restituisce false.
26/04/2012
40