Soluzione all'esercizio 2¶
Per l'esecizio 2 è opportuno ragionare allo stesso modo in cui si è ragionato per l'esercizio 1. In particolare, procediamo a strutturare il nostro script principale (main.m
) ricalcando l'andamento delle istruzioni usate in Algobuild.
Partiamo con la classica coppia clear
e clc
, le quali, come ricordiamo, servono (rispettivamente) a rimuovere le variabili esistenti dal workspace, ed a "pulire" la command window.
clear
clc
Fatto questo, possiamo richiedere all'utente il valore di \(N\), ovvero la lunghezza da assegnare al nostro vettore.
N = -1;
while N > 0
N = input("Inserire la lunghezza richiesta:\n");
end
Ricordiamo che:
1. è necessario inserire l'escape character \n
per fare in modo che, durante la visualizzazione, la stringa vada a capo;
2. dobbiamo verificare che il valore inserito sia strettamente positivo.
Parte 1: caricaVettore()
¶
Possiamo adesso creare la funzione caricaVettore()
, delegata al caricamento dello stesso. Creiamo una nuova funzione, ed inseriamo il seguente codice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Analizziamo la funzione istruzione per istruzione.
Alla prima riga, abbiamo la dichiarazione della funzione:
1 |
|
In particolare, quindi, la funzione avrà il nome caricaVettore
, accetterà come parametro formale N
, rappresentativo della lunghezza del vettore da considerare, e restituirà gli argomenti V
e modCar
. Il primo sarà proprio il vettore desiderato (V
), mentre il secondo sarà un indicatore della modalità di caricamento scelta dall'utente.
Analizziamo adesso le righe 3-7:
3 4 5 6 7 |
|
Queste righe permettono di preallocare un vettore colonna di dimensione N
, e di richiedere all'utente la modalità di caricamento del vettore, scegliendo tra 1
(caricamento manuale), 2
(caricamento casuale), e 0
(uscita dal programma).
Ovviamente, dovremo gestire tutte e tre le situazioni, oltre che il caso in cui l'utente prema per sbaglio un altro pulsante. In tal senso, potremo usare uno switch-case
.
switch modCar
case 0
disp("Uscita dal programma")
return
case 1
while i <= N
fprintf("Inserire l'elemento in posizione %d\n", i);
val = input("");
if val > 0 && mod(val, 0) == 0
i = i + 1;
else
disp("Valore non valido. Riprovare.")
end
end
case 2
disp("Generazione casuale del vettore...")
for i = 1:N
V(i) = randi(100);
end
otherwise
error("Modalità non conosciuta. Uscita dal programma.")
end
Vediamo che:
- nel
case 0
, gestiamo il caso in cuimodCar
sia pari proprio a0
. In questo caso, visualizziamo a schermo un messaggio all'utente, ed usciamo dalla funzione mediante l'istruzionereturn
; - nel
case 1
, gestiamo il caso in cuimodCar
sia pari proprio a1
. In questo caso, usiamo unwhile
per fare in modo che l'utente possa inserire manualmente i valori. Ovviamente, controlliamo che i valori siano maggiori di zero, e che il modulo 1 sia uguale a zero (e che quindi il numero sia intero). Se ciò non è vero, sarà richiesto all'utente di caricare nuovamente il valore; - nel
case 2
, gestiamo l'inserimento casuale dei valori. Per farlo, sfruttiamo la funzionerandi()
, che genera valori casuali compresi di default tra1
ed il parametro passato (in questo caso,100
); - nell'
otherwise
, chiamato in ogni altra situazione, gestiamo una situazione di errore, uscendo dal programma.
Note
Da notare come il valore massimo casuale passato sia scelto in maniera arbitraria come proprio pari a 100
.
Parte 2: ordinaVettore()
¶
Vediamo ora come ordinare il vettore caricato nel punto precedente. Scriviamo la funzione ordinaVettore()
, che implementa l'algoritmo di ordinamento selection sort.
function V = ordinaVettore(V)
for i = 1:length(V)
k = i;
for j = i+1:length(V)
if V(k) > V(j)
k = j;
end
end
tmp = V(k);
V(k) = V(i);
V(i) = tmp;
end
end
La funzione ordinaVettore(V)
accetta quindi il vettore V
in ingresso, e restituisce lo stesso vettore ordinato. Per farlo, utilizzeremo un ciclo esterno (con indice i
) ed un ciclo interno (con indice j
).
Ad ogni iterazione del ciclo esterno, andremo ad utilizzare una variabile di appoggio k
, che inizialmente sarà pari ad i
. Fatto questo, useremo un ciclo interno, che partirà dall'elemento immediatamente successivo a j
.
Verifichiamo, ad ogni iterazione del ciclo interno, se l'elemento in posizione k
sia maggiore di quello in posizione j
; se ciò è vero, provvediamo allo scambio, altrimenti questo non avviene. In altre parole, stiamo cercando il valore minimo della restante parte del vettore e, al termine del ciclo interno, lo andremo a sostituire al valore analizzato dal ciclo esterno sfruttando la variabile temporanea tmp
.
Lunghezza del vettore
Potremmo pensare di inserire come parametri formali in ingresso alla funzione ordinaVettore()
non solo V
, ma anche N
. Tuttavia, questo parametro è superfluo, visto e considerato che MATLAB ci offre la funzione length(V)
che restituisce la lunghezza del vettore passato come parametro. In alternativa, potremmo decidere di usare la funzione size(V, 1)
, che ci restituisce il numero di righe del vettore (che, nel caso di un vettore colonna, coincide anche con la lunghezza dello stesso).
Parte 3: calcolaStatistiche()
¶
Nella terza parte provvederemo a calcolare le tre statistiche richieste, ovvero minimo, massimo e media. Da notare che effettueremo questa operazione sul vettore ordinato, per cui potremo sfruttare questa caratteristica per giungere rapidamente all'individuazione dei primi due valori. Infatti, potremo scrivere la funzione come segue:
function calcolaStatistiche(V)
minimo = V(1);
massimo = V(length(V));
media = 0;
for i = 1:length(V)
media = media + V(i);
end
media = media / length(V);
end
Vediamo come il minimo
sia dato dal primo valore del vettore ordinato, mentre il massimo sia quello in posizione length(V)
che, grazie all'indicizzazione offerta dal MATLAB, è proprio quello in ultima posizione. Per ciò che riguarda invece la media, procediamo al calcolo della stessa usando un semplice ciclo for.
Nota per il calcolo delle statistiche
Ovviamente, questo modo di procedere vale soltanto nel caso il vettore sia ordinato. In caso di vettore non ordinato, il massimo ed il minimo dovranno essere calcolati mediante due semplici cicli enumerativi. Tuttavia, nel contesto della traccia, possiamo tranquillamente procedere come indicato nella funzione calcolaStatistiche()
.
Parte 4: stampa()
¶
L'ultima parte prevede la stampa a schermo del vettore. Per farlo, potremo scegliere diverse opzioni, tra cui:
- costruire una stringa e visualizzarla al termine del ciclo;
- usare la funzione
fprintf
all'interno di un ciclo; - utilizzare la funzione
disp
.
Vediamo brevemente tutte le possibili modalità:
function stampa(V)
str = "Il vettore ordinato è:\n";
for i = 1:length(V)
str = str + num2str(V(i)) + "\n";
end
fprintf(str);
end
In pratica, creeremo una stringa str
a cui concateneremo, ad ogni iterazione, il valore i
-mo di V
seguito dall'escape character \n
. Al termine, visualizzeremo la stringa creata mediante la funzione fprintf
.
Se volessimo usare la funzione fprintf
all'interno di un ciclo, dovremmo procedere come segue:
function stampa(V)
fprintf("Il vettore ordinato è: \n");
for i = 1:length(V)
fprintf("%d\n", V(i));
end
Infine, usando la funzione disp
:
function stampa(V)
disp("Il vettore ordinato è: ")
for i = 1:length(V)
disp(V(i))
end
Script complessivo¶
Combiniamo tutte le funzioni in quello che è lo script complessivo risultante.
clear
clc
N = input("Inserire la lunghezza del vettore\n");
[V, modCar] = caricaVettore(N);
if modCar == 0
return
end
V = ordinaVettore(V);
stampa(V);
Da notare che il valore modCar
viene utilizzato immediatamente dopo la chiamata a caricaVettore()
: infatti, se questo è pari a 0
, entreremo nell'istruzione condizionale mostrata alla riga 6, che terminerà immediatamente il programma grazie all'istruzione return
.
Gestione della modalità sconosciuta
In questa versione del programma, abbiamo scelto di gestire sia una modalità di inserimento non conosciuta, lanciando un errore, sia di dare all'utente la possibilità di terminare il programma. Altre modalità di gestione di tale scelta (ad esempio, forzando la scelta a soli due valori mediante un'istruzione condizionale) sono altrettanto valide nel contesto della traccia.