Array Variabili Metodi Statici Java v1
Array Variabili Metodi Statici Java v1
In effetti la memorizzazione di una stringa un po pi complicata poich la classe String speciale e ha delle particolarit che la distinguono dalle altre classi e che sono state introdotte per la rilevanza che oggi assume la gestione di stringhe in molte applicazioni (si pensi a GOOGLE). Una variabile pu essere definita di tipo derivato anche attraverso lutilizzo degli array, che rappresentano vettori di elementi tutti dello stesso tipo (che pu essere un tipo base o una classe o anche un ulteriore array come accade per una matrice che un array di array di interi o double). Se adesso definiamo un array di 3 interi come int [ ] V = {1, 2, 3}; la variabile V occupa nello stack due locazioni di 4 byte ciascuna, la prima per memorizzare lindirizzo del primo elemento dellarray nello heap e la seconda il numero di byte necessari per memorizzare tutti gli elementi pari a 12: (3 interi) (4 byte). vale variabili sono ora complessivamente memorizzate
nel seguente modo (si ricorda che un intero occupa 4 byte), cio il vettore memorizzato nello heap dallindirizzo 108 fino allindirizzo 119.
2.
Tipi
Array
Come
gi
anticipato,
in
Java
possibile
utilizzare
tipi
derivati
tra
cui
gli
array,
che
rappresentano
vettori
di
elementi
tutti
dello
stesso
tipo.
Ad
esempio:
int
[
]
X;
char
[
]
Y;
double
[
]
Z;
String
[
]
W;
definiscono
X
come
array
di
interi,
Y
come
array
di
caratteri,
Z
come
array
di
double
e
W
come
array
di
stringhe.
Per
essere
utilizzabile,
un
array
deve
essere
dimensionato
attraverso
un
apposito
comando
new.
Ad
esempio:
X
=
new
int
[20];
stabilisce
che
X
ha
20
elementi
individuati
con
appositi
indici
che
vanno
da
0
a
19.
Quindi
X[0]
il
primo
elemento
e
X[19]
lultimo
elemento.
Si
noti
che,
per
ogni
i=0..19,
X[i]
di
tipo
intero
cio
un
elemento
di
un
array
ha
come
tipo
quello
base
dellarray.
E
possibile
anche
stabilire
la
dimensione
dellarray
nel
momento
della
sua
definizione:
int
X
=
new
int
[20];
E
anche
possibile
anche
inizializzare
larray
nel
momento
della
sua
definizione:
int
Y
=
{1,2,3};
Larray
Y
viene
definito
con
dimensione
3
e
vengono
assegnati
ai
suoi
3
elementi
rispettivamente
i
valori:
1,
2
e
3.
Successivamente
alla
sua
definizione,
possibile
ridimensionare
un
array.
Ad
esempio
int
X
=
new
int
[20];
//
definizione
dellarray
X
e
sua
inizializzazione
//
attenzione
che
X
inizializzato
ma
i
suoi
20
elementi
non
ancora
System.out.println(X[5]);
//
viene
stampato
un
valore
indeterminato
valore
non
inizializzato
System.out.println(X[20]);
//
viene
segnalato
errore:
lelemento
20.mo
non
esiste
for
(
int
i
=0;
i
<
20;
i++
)
X[i]=i;
//
ora
vengono
inizializzati
gli
elementi
di
X
System.out.println(X[5]);
//
viene
stampato
il
valore
5
System.out.println(X[40]);
//
errore:
lelemento
40.mo
non
esiste
for
(
int
i
=0;
i
<
20;
i++
)
System.out.println(X[i]);
//
vengono
stampati
i
venti
elementi
di
X
X
=
new
int
[40];
//
viene
ridefinito
larray
X
che
ora
ha
40
elementi
//
attenzione
che
i
20
elementi
precedenti
ora
sono
cancellati
for
(
int
i
=0;
i
<
40;
i++
)
X[i]=i;
//
ora
vengono
inizializzati
i
nuovi
40
elementi
di
X
for
(
int
i
=0;
i
<
40;
i++
)
System.out.println(X[i]);
//
vengono
stampati
i
nuovi
quaranta
elementi
di
X
Larray
X
viene
prima
dimensionato
con
20
elementi
e
poi
ridimensionato
con
40
elementi.
Subito
dopo
il
ridimensionamento,
tutti
i
dati
precedenti
non
sono
pi
utilizzabili
(
come
se
venissero
cancellati).
E
possibile
anche
definire
un
array
di
array,
ad
esempio:
int
[
]
X;
int
[]
[]
U;
int
k;
U
=
new
int
[5][10];
X
=
U[3];
k
=
U[3][9];
La
variabile
U
rappresenta
una
matrice
di
5
righe
e
10
colonne.
Con
il
comando
X
=
U[3]
copiamo
la
4^
riga
(si
ricorda
che
lindice
parte
da
0)
di
U
in
X.
Con
il
comando
k
=
U[3][9]
copiamo
lelemento
della
4^
riga
e
della
10^
colonna
in
k.
Un
primo
esempio
di
utilizzo
degli
array,
l'abbiamo
gi
visto
nella
codifica
di
un
intero
relativo
in
16
bit
con
complemento
a
due
allorquando
abbiamo
utilizzato
un
array
per
memorizzare
le
cifre
binarie
mana
mano
che
venivano
prodotte
e
poi
stamparle
alla
fine
nell'ordine
giusto.
Come
secondo
esempio
di
utilizzo
degli
array,
scriviamo
un
programma
che
legge
una
stringa
e
per
ogni
carattere
di
essa,
determina
il
numero
di
occorrenze
(frequenza)
nella
stringa.
Ad
esempio,
se
la
stringa
cara
carla,
il
carattere
c
ha
frequenza
2,
a
4,
r
2,
l
1.
public static void main(String [] args){ Scanner reader = new Scanner(System.in); System.out.println("Introduci il testo"); String testo = reader.next(); int n = testo.length(); // viene definito un array elencoCar di massimo n caratteri // in cui memorizzare tutti i possibili caratteri diversi di testo // nel caso peggiore ci saranno n caratteri diversi // ma in generale ce ne saranno di meno essendoci caratteri duplicati char [] elencoCar = new char [n]; // viene definito un array freqCar di massimo n interi // se elencoCar[5] vale c e freqCar[5] vale 3 // significa che il carattere c ha frequenza 3 int [] freqCar = new int [n]; // m indica il numero di caratteri differenti nel testo int m = 0; // inizialmente 0 caratteri diversi in testo for ( int i = 0; i < n; i++ ) { char carCorr = testo.charAt(i); // carattere i-mo in testo // verifica se carCorr gi in elencoCar o va inserito boolean trovatoCar = false; for ( int j = 0; j < m && !trovatoCar; j++ ) if ( carCorr == elencoCar[j] ) { // carCorr in elencoCar, // quindi va incrementata la frequenza trovatoCar = true; freqCar[j]++; } if ( !trovatoCar ) { // carCorr non in elencoCar // carCorr va inserito in elencoCar con frequenza 1 elencoCar [m] = carCorr; freqCar[m]=1; m++; // va incrementato il numero di caratteri diversi } }; System.out.println("Frequenze dei caratteri"); for ( int i = 0; i < m; i++ ) { System.out.print("Carattere <" + elencoCar[i]+">: "); System.out.println(freqCar[i]); };
}
3
Si noti che sono utilizzati due array: larray di caratteri elencoCar e larray di interi freqCar. Entrambi sono dimensionati con un numero di elementi pari alla lunghezza della stringa testo. Tuttavia, in generale non tutti questi elementi sono utilizzati in quanto i due array contengono tanti elementi quanti sono i caratteri differenti di testo. Gli elementi dei due array sono costruiti iterativamente, attraverso la scansione di tutti i caratteri di testo: per ogni carattere, si va a verificare se esso gi compreso in elencoCar ; se presente, si incrementa di 1 la relativa frequenza; altrimenti si aggiunge il carattere a elencoCar e si pone la relativa frequenza a 1.
Nello
scrivere
un
programma
opportuno
seguire
alcune
regole
di
buona
scrittura.
Una
di
queste
consiste
nel
suddividere
un
programma
in
unit
specializzate
a
svolgere
particolari
funzioni.
Tali
unit
di
programmazione
sono
chiamati
metodi
e
sono
definiti
in
maniera
analoga
al
metodo
main.
Essi
vengono
richiamati
dal
main
o
da
altri
metodi.
Alla
chiamata
del
metodo,
vanno
passati
tutti
i
parametri
indicati
nella
definizione
del
metodo.
Quando
ha
completato
la
sua
esecuzione,
il
metodo
o
non
restituisce
nulla
o
restituisce
un
valore
di
un
tipo
predefinito.
Come
primo
esempio
si
consideri
la
seguente
traccia
dellesercizio
2
dellappello
del
22/07/2011.
Traccia:
Si
scriva
un
metodo
Java
comprimi
che
riceve
in
ingresso
un
vettore
di
interi
V
e
restituisce
un
vettore
di
interi
C
che
ne
rappresenta
la
versione
compressa.
Il
processo
di
compressione
fa
corrispondere
ad
una
sequenza
ininterrotta
di
K
interi
N
nel
vettore
V,
la
sequenza
(K,N)
nel
vettore
C.
Ad
esempio,
se
V=[1,1,1,1,3,3,4,3,7,7,7,7,7]
allora
C=[4,1,
2,3,
1,4,
1,3,
5,7].
Soluzione:
Scriviamo
la
soluzione
come
un
metodo
statico
Java
di
nome
comprimi
che
riceve
in
ingresso
un
array
di
interi
V
(un
solo
parametro
formale)
e
restituisce
un
array
di
interi:
static int [ ] comprimi ( int [ ] V ) { int [ ] K = new int[V.length*2]; // caso peggiore di elementi tutti // distinti int iK = 0; // indice del vettore K int iV = 0; // indice del vettore V while ( iV < V.length ) { // scandiamo tutti gli elementi di V int iV1; boolean elemDiff=false; // indica se trovato un elemento differente for ( int j = iV+1; j < V.length && !elemDiff; j++ ) if ( V[j] != V[iV] ) { iV1 = j; elemDiff = true; } if ( !elemDiff ) iV1 = V.length; K[iK] = iV1 - iV; // viene memorizzato il numero di ripetizioni K[iK+1] = V[iV]; // viene memorizzato lelemento ripetuto iK += 2; // lindice di K viene incrementato di 2 iV = iV1; // la scansione di V riparte dallindice iV1 } int [ ] C = new int[iK] // dimensione effettiva di C for ( int i = 0; i < iK; i++ ) C[i] = K[i]; // viene ricopiato K in C return C; }
La soluzione per lesame tutta qui. Ma se si vuole provare il metodo necessario inserirlo in una classe insieme a un metodo main (ed eventuali ulteriori altri metodi):
Class Compressione { static public void main (String [] args) { int [] V= leggiVettore (); int [] C = comprimi(V); stampaVettore(C); } static int [ ] comprimi ( int [ ] V ) { // vedi codice precedente } static int [] leggiVettore () { Scanner reader = new Scanner(System.in); System.out.println("Numero di elementi del vettore V?"); int n = reader.nextInt(); int [] V = new int[n]; for ( int i = 0; i < n; i++ ) { System.out.println("V["+i+"]?"); V[i] = reader.nextInt(); } return V; } static void stampaVettore ( int [] C) { System.out.println("Compressione di V"); System.out.print("[ "); // senza salto linea for ( int i = 0; i < C.length; i+=2 ) { System.out.print( C[i]+":"+C[i+1]); // senza salto linea if ( i < C.length-2 ) System.out.print( ", "); // senza salto linea } System.out.println(" ]"); // salto linea System.out.println("bye"); } }
Lutilit di utilizzare metodi piuttosto che inserire direttamente il codice nel metodo main essenzialmente quella di evitare di distrarsi con limplementazione di dettagli secondari (tali sono da considerare due semplici metodi di lettura e scrittura di un array), rimandandola a un secondo momento o, ancora meglio, cercando di utilizzare metodi gi scritti (eventualmente opportunamente modificati).
Come
un
secondo
esempio
si
consideri
il
seguente
metodo
per
il
calcolo
del
fattoriale
di
un
numero
n,
calcolato
come
12(n-1)
n:
static int fattoriale ( int n ) { if ( n < 2 ) return 1; else { int ris = 2; for ( int i =3; i <= n; i++ ) ris = ris*i; return ris; } }
Esso
restituisce
un
intero
e
ha
un
parametro
formale
(la
variabile
n)
di
tipo
intero.
Per
richiamare
il
metodo
bisogna
scrivere
il
nome
del
metodo
(nellesempio
fattoriale
e
passare
un
parametro
attuale
di
tipo
intero,
cio
un
valore
effettivo
per
il
quale
calcolare
il
fattoriale.
Il
metodo
restituisce
un
intero.
Ad
esempio
il
metodo
pu
essere
richiamato
con
listruzione:
int R = fattoriale(4);
Dopo
la
chiamata,
la
variabile
di
R
conterr
24,
cio
il
fattoriale
di
4.
Il
metodo
restituisce
1
se
gli
viene
passato
un
numero
negativo.
Volendo
eliminare
questo
inconveniente,
potremmo
interpretare
che
fattoriale(-n)
con
n
negativo,
corrisponda
a
fattoriale(n)
e
riscrivere
il
metodo
come:
static int fattoriale ( int n ) { int segno = 1; if ( n < 0) { n = -n; segno =-1; } if ( n < 2 ) return 1*segno; else { int ris = 2; for ( int i =3; i <= n; i++ ) ris = ris*i; return ris * segno; } }
Ora
presentiamo
il
metodo
fibonacci
si
ricorda
che
fibonacci(0)
vale
0,
fibonacci(1)
vale
1
e
per
ogni
i
>
1,
fibonacci(i)
=
fibonacci(i-1)+fibonacci(i-2).
La
sequenza
dei
primi
numeri
di
Fibonacci
:
0,
1,
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765.
static int fibonacci ( int n ) { if (n < 2 ) return n; else { int F1 = 1, F2=0, F=1; for (int i= 3; i <= n; i++ ){ F2=F1; F1=F; F=F1+F2; } return F; } } // fine metodo fibonacci
Di
seguito
presentiamo
una
classe
con
3
metodi:
il
metodo
main,
lanciato
automaticamente
con
lavvio
della
classe,
che
a
sua
volta
richiama
i
metodi
fattoriale
e
fibonacci.
public class CalcolaFF { public static void main(String[] args) { Scanner reader = new Scanner(System.in); // prima lettura del comando di interazione System.out.print("Inserisci A per calcolare fattoriale, System.out.println("B per fibonacci e C per finire [A/B/C]?"); char comando = Character.toUpperCase(reader.nextChar()); // sessione interattiva while ( comando == 'A' || comando == 'B' ) { System.out.println("Inserisci n "); int n = reader.nextInt(); int ris; if (comando =='A') { System.out.print("Fattoriale = "); ris = fattoriale(n); System.out.println(ris); // si pu anche scrivere direttamente solo una istruzione // System.out.println(fattoriale(n));
} else { System.out.print("Fibonacci = "); ris = fibonacci(n); System.out.println(ris); // si pu anche scrivere direttamente solo una istruzione // System.out.println(fibonacci(n)); } // successiva lettura del comando di interazione System.out.print("Inserisci A per calcolare fattoriale, System.out.println("B per fibonacci e C per finire [A/B/C]?"); comando = Character.toUpperCase(reader.nextChar()); } System.out.println("bye"); } // fine metodo main // METODO FATTORIALE static int fattoriale ( int n ) { // vedi codice precedente } // fine metodo fattoriale // METODO FIBONACCI static int fibonacci ( int n ) { // vedi codice precedente } } // fine metodo fibonacci } // fine classe CalcolaFF
Come
secondo
esempio
di
utilizzo
di
metodi,
consideriamo
nuovamente
il
programma
che
calcola
le
frequenze
di
caratteri
in
un
testo.
Vogliamo
aggiungere
una
sessione
interattiva
che
permetta
allutente
di
chiedere
se
vuole
conoscere
la
frequenza
di
un
dato
carattere
o
quali
sono
i
caratteri
con
frequenza
maggiore
o
uguale
ad
un
dato
valore.
Piuttosto
che
estendere
il
programma
e
renderlo
meno
leggibile
(un
metodo
non
dovrebbe
mai
essere
troppo
lungo),
possiamo
definire
due
appositi
metodi:
// METODO trovaFrequenzaCar static void trovaFrequenzaCar ( Scanner reader, char[] C, int [] F, int m) { // dato un carattere, viene verificato se presente nell'elenco C // se presente ne viene stampata la frequenza System.out.println("Carattere?"); char car= reader.nextChar(); boolean trovato = false; for (int i =0; i < m && !trovato; i++ ) { if ( C[i] == car ) { trovato = true; System.out.println("Carattere <" + C[i]+">: "+F[i]); } }; if (!trovato ) System.out.println("Carattere <" + car+"> non presente."); } // fine metodo trovaFrequenzaCar // METODO trovaCarFrequenti static void trovaCarFrequenti (Scanner reader, char[] C, int [] F, int m) { // data una frequenza minima fMin, vengono individuati tutti i caratteri // nell'elenco che abbiano una frequenza di almeno fMin System.out.println("Frequenza minima?"); int fMin = reader.nextInt(); for (int i =0; i < m; i++ )
if ( F[i] >= fMin ) System.out.println("Carattere <" + C[i]+">: "+F[i]); } fine metodo trovaCarFrequenti
Si
noti
che
entrambi
i
metodi
fanno
utilizzano
loggetto
reader
definito
nel
main
e
passato
come
parametro.
Pertanto
abbiamo
due
possibilit:
o
passarlo
come
parametro
(ma
non
labbiamo
inserito
tra
i
parametri
formali)
o
definire
reader
come
variabile
statica.
Vediamo
come
realizzare
questultima
soluzione:
public class ContaCaratteri { Scanner reader = new Scanner(System.in); // variabile statica inizializzata public static void main(String [] args){ Scanner reader = new Scanner(System.in); System.out.println("Introduci il testo"); String testo = reader.next(); // . . . // vedi codice precedente // . . . System.out.println("Frequenze dei caratteri"); for ( int i = 0; i < m; i++ ) { System.out.print("Carattere <" + elencoCar[i]+">: "); System.out.println(freqCar[i]); }; // parte aggiuntiva char comando; do { // sessione interattiva con l'utilizzatore System.out.print("Frequenza di un Carattere o); System.out.print(" Caratteri pi Frequenti o Fine? (A/B/C)"); comando = Character.toUpperCase(reader.nextChar()); if ( comando == 'A' ) trovaFrequenzaCar(reader,elencoCar,freqCar,m); else if ( comando == 'B' ) trovaCarFrequenti (reader,elencoCar,freqCar,m); } while ( comando != 'C' ); System.out.println("Bye");
} // fine main
// inserire qui le definizioni di
trovaFrequenzaCar e trovaCarFrequenti
}
//
fine
classe
ContaCaratteri
Si
noti
che
lestensione
del
metodo
main
limitata
a
poche
linee
di
codice
e
le
due
nuove
funzioni
aggiunte
sono
rese
astratte
attraverso
il
ricorso
a
due
appositi
metodi.
Lutilizzo
di
astrazione
ci
permette
di
scrivere
un
programma
senza
dover
fornire
tutti
i
dettagli
implementativi.
Ovviamente,
alla
fine
essi
dovranno
essere
forniti
cio
i
metodi
dovranno
essere
scritti.
Ma
rinviare
la
scrittura
risulta
estremamente
utile
per
un
approccio
sistematico
in
cui
si
parte
dai
concetti
generali
per
poi
passare
a
concetti
pi
specifici
e
dettagliati:
si
parla
di
stepwise
refinement
(raffinamento
dei
concetti
a
passi
successivi).
Addirittura
il
main
nellesempio
potrebbe
essere
ridotto
ulteriormente
spostando
una
parte
del
codice
in
un
apposito
metodo
CalcolaFrequenzaCar:
public static void main(String [] args){ Scanner reader = new Scanner(System.in); System.out.println("Introduci il testo"); String testo = reader.next(); int n = testo.length(); char [] elencoCar = new char [n]; int [] freqCar = new int [n]; int m = calcolaFrequenzaCar(testo, elencoCar, freqCar); System.out.println("Frequenze dei caratteri");
for ( int i = 0; i < m; i++ ) { System.out.print("Carattere <" + elencoCar[i]+">: "); System.out.println(freqCar[i]); }; char comando; do { // sessione interattiva con l'utilizzatore System.out.print("Frequenza di un Carattere o); System.out.print(" Caratteri pi Frequenti o Fine? (A/B/C)"); comando = Character.toUpperCase(reader.nextChar()); if ( comando == 'A' ) trovaFrequenzaCar(reader,elencoCar,freqCar,m); else if ( comando == 'B' ) trovaCarFrequenti (reader,elencoCar,freqCar,m); } while ( comando != 'C' ); System.out.println("Bye"); } // fine main
static int calcolaFrequenzaCar ( String testo, char [] elencoCar, int [] freqCar ) { int n = testo.length(); int m = 0; for ( int i = 0; i < n; i++ ) { char carCorr = testo.charAt(i); boolean trovatoCar = false; for ( int j = 0; j < m && !trovatoCar; j++ ) if ( carCorr == elencoCar[j] ) { trovatoCar = true; freqCar[j]++; } if ( !trovatoCar ) { elencoCar [m] = carCorr; freqCar[m]=1; m++; } }; return m, }
Come
ulteriore
esempio
torniamo
alla
traccia
del
22/07/2011.
La
soluzione
pu
essere
scritta
ne
seguente
moto
utilizzando
un
metodo
primoDiverso
che
riceve
come
parametri
formali
un
array
di
interi
W
e
un
intero
k
e
restituisce
un
intero
che
rappresenta
lindice
del
primo
elemento
di
W
successivo
a
W[k]
che
diverso
da
W[k].
static int [ ] comprimi ( int [ ] V ) { int [ ] K = new int[V.length*2] int iK = 0, iV = 0; while ( iV < V.length ){ int iV1 = primoDiverso(V,iV); K[iK] = iV1 iV; K[iK+1] = V[iV]; iK += 2; iV = iV1; } int [ ] C = new int[iK] // dimensione effettiva di C for ( int i = 0; i < iK; i++ ) C[i] = K[i]; return C; }
static int primoDiverso( int [ ] W, int k ) { for ( int i = k+1; i < W.length; i++ ) if ( W[k] != W[i] ) return i; return W.length; }
Il vantaggio delluso del metodo solo nella chiarezza della lettura del programma e nella maggiore facilit di scrittura di esso, derivante dal meccanismo potente dellastrazione: possiamo scrivere il programma assumendo che esista un metodo che svolga una certa funzione che per il momento non vogliamo implementare. Limplementazione viene rimandata a un secondo momento o addirittura evitata se si riesce ad affidare il compito ad altri o a trovarla gi disponibile. Per concludere, sottolineiamo che i metodi introdotti sono di tipo statico nel senso che sono metodi della classe e non di oggetti della classe. E possibile definire anche metodi non statici, ma essi non saranno trattati nel corso, anche se ne saranno utilizzati alcuni in effetti i metodi di lettura associati a reader sono metodi non statici.
Quando
un
metodo
richiama
un
altro
metodo,
deve
condividere
con
esso
alcune
variabili
sulle
quali
il
metodo
chiamato
deve
effettuare
i
suoi
calcoli.
Il
modo
pi
utilizzato
quello
di
passare
tali
variabili
come
parametri.
Ma
anche
possibile
definire
allinterno
della
classe
alcune
variabili
statiche
che
sono
visibili
a
tutti
i
metodi
della
classe.
Ad
esempio
la
variabile
n
su
cui
va
effettuato
il
calcolo
del
fattoriale
o
del
Fibonacci,
invece
di
passare
tale
valore
come
parametro
attuale,
n
pu
essere
definita
come
variabile
statica
nel
seguente
modo:
public class CalcolaFF { static int n; // variabile statica public static void main(String[] args) { // prima lettura del comando di interazione System.out.print("Inserisci A per calcolare fattoriale, System.out.println("B per fibonacci e C per finire [A/B/C]?"); char comando = Character.toUpperCase(reader.nextChar()); // sessione interattiva while ( comando == 'A' || comando == 'B' ) { System.out.println("Inserisci n "); n = reader.nextInt(); // la variabile n gi definita if (comando =='A') { System.out.print("Fattoriale = "); // a fattoriale non viene passato alcun parametro attuale System.out.println(fattoriale()); } else { System.out.print("Fibonacci = "); // a fibonacci non viene passato alcun parametro attuale System.out.println(fibonacci()); } // successiva lettura del comando di interazione System.out.print("Inserisci A per calcolare fattoriale, System.out.println("B per fibonacci e C per finire [A/B/C]?"); comando = Character.toUpperCase(reader.nextChar()); } System.out.println("bye"); } // fine metodo main
10
// METODO FATTORIALE static int fattoriale ( ) { // nessun parametro formale if (n < 2 ) return 1; else { int ris = 2; for (int i= 3; i <= n; i++ ) ris = ris*i; return ris; } } // fine metodo fattoriale // METODO FIBONACCI static int fibonacci ( ) { // nessun parametro formale if (n < 2 ) return n; else { int F1 = 1, F2=0, F=1; for (int i= 3; i <= n; i++ ){ F2=F1; F1=F; F=F1+F2; } return F; } } // fine metodo fibonacci } // fine classe CalcolaFF
Ritornando
al
programma
sulla
frequenza
dei
caratteri
in
una
stringa,
possiamo
evitare
di
passare
i
vari
parametri
alle
funzioni
richiamate
definendole
come
statica
nel
seguente
modo:
public class ContaCaratteri { Scanner reader = new Scanner(System.in); // variabile statica inizializzata static String testo; static char[] elencoChar; statica int [] freqCar public static void main(String [] args){ System.out.println("Introduci il testo"); testo = reader.next(); // gi definito int n = testo.length(); elencoCar = new char [n]; // gi definito freqCar = new int [n]; // gi definito int m = calcolaFrequenzaCar(); // nessun parametro // utilizzate variabili statiche System.out.println("Frequenze dei caratteri"); for ( int i = 0; i < m; i++ ) { System.out.print("Carattere <" + elencoCar[i]+">: "); System.out.println(freqCar[i]); }; char comando; do { // sessione interattiva con l'utilizzatore System.out.print("Frequenza di un Carattere o); System.out.print(" Caratteri pi Frequenti o Fine? (A/B/C)"); comando = Character.toUpperCase(reader.nextChar()); if ( comando == 'A' ) trovaFrequenzaCar(m); else if ( comando == 'B' ) trovaCarFrequenti (m);
11
} while ( comando != 'C' ); System.out.println("Bye"); } // fine main // METODO calcolaFrequenzaCar senza parametri formali static int calcolaFrequenzaCar ( ) { } // fine metodo calcolaFrequenzaCar // METODO trovaFrequenzaCar con un solo parametro formale static void trovaFrequenzaCar ( int m ) { // istruzioni non modificate // ... } // fine metodo trovaFrequenzaCar // METODO trovaCarFrequenti con un solo parametro formale static void trovaCarFrequenti ( int m ) { // istruzioni non modificate // ... } fine metodo trovaCarFrequenti
} // fine classe ContaCaratteri Non esistono regole precise se utilizzare parametri o variabili statiche. Unindicazione di massima che lutilizzo di parametri rende il metodo pi leggibile (abbiamo sottomano tutte le variabili utilizzate nel metodo senza dover consultare le variabili statiche della classe) e autosufficiente (il metodo pu essere utilizzato senza dover riportarsi le variabili statiche). Il suggerimento quindi di utilizzare i parametri formali il pi possibile.
4. Ulteriori Esercizi
Una palindroma una stringa che pu essere letta in entrambe le direzioni, ad esempio otto oppure ai lati dItalia. In effetti questultima stringa una palindroma solo se si trascurano gli spazi e i caratteri differenti da lettere quale lapice. Se si escludo gli spazi anche questa una palindroma: In girum imus nocte et consumimur igni. Provate a scrivere un metodo che riceve una stringa e risponde true se una palindroma considerando solo le lettere e saltando tutti gli altri caratteri compresi gli spazi. Un altro esercizio il secondo dellappello del 5/0/2011: Traccia: Si scriva un metodo Java verificaSottoVettori che riceve in ingresso due vettori di interi V e W, ognuno dei quali contiene valori distinti, restituisce true se e solo se gli elementi di W sono una sotto- sequenza inversa degli elementi di V, cio gli elementi di W sono tutti contenuti in V (anche se ne possono mancare alcuni di essi) e sono riportati nella stessa sequenza inversa in cui occorrono nel vettore V. Ad esempio, se V=[5,6,1,4,9,2,8,7] e W=[7,4,6,5] allora il metodo restituisce true mentre con W = [5,6,4,7] o W = [4,7,6,5] il metodo restituisce false. Soluzione:
static boolean verificaSottoVettori ( int [ ] V, int [ ] W ) { if ( !tuttiDistinti(V) || !tuttiDistinti(W) ) return false; int pos = 0; for ( int i = W.length-1; i >=0; i-- ) { pos = compresoDaPos(W[i],V,pos)+1; if ( pos == 0 ) return false; // oppure return pos != 0 } return true;
12
} static int compresoDaPos( int X, int [ ] V, int k ) { for ( int i = k; i < V.length; i++ ) if ( X == V[i] ) return i; return -1; } static boolean tuttiDistinti( int [ ] K ) { for ( int i = 0; i < K.length-1; i++ ) if ( compresoDaPos(K[i],K,i+1) >= 0 ) return false; return true; }
E interessante notare che lo stesso metodo compresoDaPos sia utilizzato da una parte per verificare la propriet di sottostringa definita dalla traccia e dallaltra per verificare preliminarmente che entrambi i vettori contengano tutti elementi distinti.
13