• Non ci sono risultati.

10 - Programmare con gli Array Programmazione e analisi di dati Modulo A: Programmazione in Java Paolo Milazzo

N/A
N/A
Protected

Academic year: 2022

Condividi "10 - Programmare con gli Array Programmazione e analisi di dati Modulo A: Programmazione in Java Paolo Milazzo"

Copied!
29
0
0

Testo completo

(1)

10 - Programmare con gli Array

Programmazione e analisi di dati Modulo A: Programmazione in Java

Paolo Milazzo

Dipartimento di Informatica, Universit`a di Pisa http://www.di.unipi.it/∼milazzo

milazzo di.unipi.it

Corso di Laurea Magistrale in Informatica Umanistica A.A. 2016/2017

(2)

Programmare con gli array

Lo scopo di questa lezione `e illustrare alcuni schemi di programmi cio`e soluzioni a problemi di programmazione che ricorrono frequentemente nello sviluppo di programmi

sono essenzialmente degli algoritmi, espressi nel linguaggio di programmazione scelto (Java)

Ci concentreremo su problemi che richiedono ciclie arrayper essere risolti Quindi: schemi di programmiiterativi

Per ogni schema di programma che consideremo:

Vedremo un esempiodi problema e il programma che lo risolve Ragioneremo sul programma dell’esempio per estrarnelo schemadi funzionamento

Menzioneremo altri esempidi problemi che possono essere risolti seguendo lo stesso schema

(3)

Innanzitutto: quando gli array non servono? (1)

Innanzitutto `e bene capire che non sempre serve usare un array.

Esempio: programma che chiede all’utente di inserire 10 numeri e ne calcola la media

i m p o r t j a v a . u t i l . S c a n n e r ;

p u b l i c c l a s s M e d i a { // s o l u z i o n e che usa un a r r a y p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

S c a n n e r i n p u t = new S c a n n e r ( S y s t e m . in );

int[] v a l o r i = new int[ 1 0 ] ;

// m e m o r i z z a t u t t i i v a l o r i in un a r r a y for (int i =0; i < 1 0 ; i ++)

v a l o r i [ i ] = i n p u t . n e x t I n t ();

// s o m m a t u t t i gli e l e m e n t i d e l l ’ a r r a y int s o m m a = 0;

for (int x : v a l o r i ) s o m m a += x ; // c a l c o l a e s t a m p a la m e d i a int m e d i a = s o m m a / 1 0 ;

S y s t e m . out . p r i n t l n (" La m e d i a e ’: " + m e d i a );

} }

(4)

Innanzitutto: quando gli array non servono? (2)

Prima di creare un array e iniziare a riempirlo di valori, pensare bene se c’e’ un modo per ottenere lo stesso risultato lavorando on-the-fly

ossia utilizzando i dati man mano che arrivano, senza memorizzarli

i m p o r t j a v a . u t i l . S c a n n e r ;

p u b l i c c l a s s M e d i a 2 { // s o l u z i o n e che NON usa un a r r a y p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

S c a n n e r i n p u t = new S c a n n e r ( S y s t e m . in );

// s o m m a on - the - fly t u t t i gli e l e m e n t i i n s e r i t i int s o m m a = 0;

for (int i =0; i < 1 0 ; i ++) s o m m a += i n p u t . n e x t I n t ();

// c a l c o l a e s t a m p a la m e d i a int m e d i a = s o m m a / 1 0 ;

S y s t e m . out . p r i n t l n (" La m e d i a e ’: " + m e d i a );

} }

(5)

Innanzitutto: quando gli array non servono? (3)

Altro esempio dello stesso tipo...

Esempio: scrivere un programma che stampa gli elementi di un array in ordine inverso

i m p o r t j a v a . u t i l . S c a n n e r ;

p u b l i c c l a s s I n v e r t i { // s o l u z i o n e che usa un s e c o n d o a r r a y p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

int[] v a l o r i = { 5 , 7 , 9 , 11 , 23 , 8 };

int l a s t = v a l o r i . length -1; // p o s i z i o n e d e l l ’ u l t i m o e l e m e n t o // c r e o un n u o v o a r r a y in cui c o p i o i v a l o r i in o r d i n e i n v e r s o int[] v a l o r i 2 = new int[ v a l o r i . l e n g t h ];

for (int i =0; i < v a l o r i . l e n g t h ; i ++) v a l o r i 2 [ i ] = v a l o r i [ last - i ];

// s t a m p a il c o n t e n u t o del s e c o n d o a r r a y for (int x : v a l o r i 2 )

S y s t e m . out . p r i n t l n ( x );

}

(6)

Innanzitutto: quando gli array non servono? (4)

Ma... serve veramente il secondo array?

I dati sono gi`a memorizzati nel primo. Basta eseguire le stampe in ordine inverso...

i m p o r t j a v a . u t i l . S c a n n e r ;

p u b l i c c l a s s I n v e r t i 2 { // s o l u z i o n e che NON usa un s e c o n d o a r r a y p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

int[] v a l o r i = { 5 , 7 , 9 , 11 , 23 , 8 };

// s c o r r e l ’ a r r a y d a l l ’ u l t i m o e l e m e n t o al p r i m o // n o t a r e l ’ uso d e g l i i n d i c i nel c i c l o for for (int i =( v a l o r i . length - 1 ) ; i > = 0 ; i - -)

S y s t e m . out . p r i n t l n ( v a l o r i [ i ]);

}

(7)

Innanzitutto: quando gli array non servono? (5)

In quali di questi esempi `e necessario un array?

1. Chiedere all’utente di inserire 10 numeri e stampare il minimo tra essi 2. Chiedere all’utente di inserire 10 stringhe e stampare la stringa

ottenuta concatenandole tutte l’una dopo l’altra

3. Chiedere all’utente di inserire 10 numeri e, successivamente, ristamparli tutti nell’ordine

4. Chiedere all’utente di inserire 10 caratteri e stampare Trovata Vocale! se tra essi `e presente almeno una vocale

5. Chiedere all’utente di inserire 10 numeri e verificare se i primi 5 sono uguali agli ultimi 5 (ad es. 1,3,4,7,9,1,3,4,7,9)

Soluzione: NNSNS

Quanto deve essere grande l’array nel caso 5?

(8)

Innanzitutto: quando gli array non servono? (5)

In quali di questi esempi `e necessario un array?

1. Chiedere all’utente di inserire 10 numeri e stampare il minimo tra essi 2. Chiedere all’utente di inserire 10 stringhe e stampare la stringa

ottenuta concatenandole tutte l’una dopo l’altra

3. Chiedere all’utente di inserire 10 numeri e, successivamente, ristamparli tutti nell’ordine

4. Chiedere all’utente di inserire 10 caratteri e stampare Trovata Vocale! se tra essi `e presente almeno una vocale

5. Chiedere all’utente di inserire 10 numeri e verificare se i primi 5 sono uguali agli ultimi 5 (ad es. 1,3,4,7,9,1,3,4,7,9)

Soluzione: NNSNS

Quanto deve essere grande l’array nel caso 5?

(9)

Schemi di programmi su array

D’ora in poi assumeremo che i dati su cui vogliamo lavorare siano contenuti in un array

Vedremo solo frammenti di programmida inserire nel seguente scheletro

i m p o r t j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s N o m e P r o g r a m m a {

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) { S c a n n e r i n p u t = new S c a n n e r ( S y s t e m . in );

int[] v a l o r i = int[ 1 0 ] ; // l ’ a r r a y in q u e s t i o n e // i n i z i a l i z z a z i o n e da p a r t e d e l l ’ u t e n t e

for (int i =0; i < 1 0 ; i ++) v a l o r i [ i ] = i n p u t . n e x t I n t ();

// I F R A M M E N T I DI P R O G R A M M I CHE V E D R E M O // D O V R A N N O E S S E R E I N S E R I T I QUI

} }

(10)

Scansione sequenziale di un array (1)

Esempio: Sommare tutti i valori di un array

int s o m m a =0;

for (int x : v a l o r i ) s o m m a += x ;

S y s t e m . out . p r i n t l n ( s o m m a );

Si scandisce tutto l’array dall’inizio alla fine “portandosi dietro” la somma dei valori incontrati

All’i-esima iterazione la variabile (accumulatore) somma rappresenta in modo sinteticotutti gli elementi dell’array tra le posizioni 0 e i-1 In altre situazioni la variabile da “portarsi dietro” pu`o essere

I uncontatore(Esempio: stampare quanti zeri sono contenuti nell’array)

I unvalore (Esempio: stampare il valore minimo)

I unindice(Esempio: stampare la posizione del valore minimo)

I combinazioni delle precedenti(Esempi: stampare valore e posizione del minimo; stampare minimo e massimo)

(11)

Scansione sequenziale di un array (2)

Schema di programma: scansione sequenziale 1. Dichiara e inizializza variabili

opportune X,Y,... (da "portarsi dietro") 2. Per ogni elemento E dell’array

aggiorna le variabili X,Y,... considerando E 3. Stampa il risultato sulla base dei valori finali

di X,Y,...

(12)

Scansione sequenziale di un array (3)

Altri esempi in cui pu`o essere applicato questo schema:

1. Dato un array di stringhe stampare la stringa pi`u lunga

2. Verificare se un dato elemento `e presente in un array (terminologia:

problema della ricercadi un elemento)

3. In un array di caratteri, stampare il numero di occorrenze di ogni vocale (es: "Ci sono 5 a, 3 e, 7 i, 0 o, 9 u")

4. Verificare se i valori di un array sono in ordine crescente Che informazioni bisogna “portarsi dietro” in ogni caso?

(13)

Scansione a doppio indice di un array (1)

Esempio: Inversione di un array: ridisporre gli elementi dell’array in ordine inverso (dall’ultimo al primo)

Da cos`ı:

valori 7 6 12 667 -33 0 13 -34 4 100

0 1 2 3 4 5 6 7 8 9

A cos`ı:

valori 100 4 -34 13 0 -33 667 12 6 7

0 1 2 3 4 5 6 7 8 9

Ideesu come fare?

(14)

Scansione a doppio indice di un array (2)

Idea: scambio il primo elemento con l’ultimo, il secondo con il penultimo, ecc...

Attenzione: come si scambiano i valori di due elementi dell’array?

NON in questo modo:

v a l o r i [0] = v a l o r i [ 9 ] ;

v a l o r i [9] = v a l o r i [ 0 ] ; // A A A R G H !! che f i n e ha f a t t o v a l o r i [ 0 ] ?

CI VUOLE unavariabile d’appoggio:

int tmp = v a l o r i [ 0 ] ; v a l o r i [0] = v a l o r i [ 9 ] ; v a l o r i [9] = tmp ;

Lo stesso vale quando si vogliono scambiare i valori di due normali variabili

(15)

Scansione a doppio indice di un array (3)

Ecco la soluzione:

for (int i =0; i <( v a l o r i . l e n g t h / 2 ) ; i ++) { // n o t a r e la g u a r d i a // p o s i z . e l e m . da s c a m b i a r e con q u e l l o in p o s i z i o n e i int j =( v a l o r i . length -1) - i ;

int tmp = v a l o r i [ i ];

v a l o r i [ i ] = v a l o r i [ j ];

v a l o r i [ j ] = tmp ; }

oppure

for (int i =0 , j = v a l o r i . length -1; i < j ; i ++ , j - -) { // n o t a r e la g u a r d i a int tmp = v a l o r i [ i ];

v a l o r i [ i ] = v a l o r i [ j ];

v a l o r i [ j ] = tmp ; }

In questo caso stiamo usando due indici, i e j, per muoverci nell’array In questo caso i e j sono entrambi aggiornati ad ogni iterazione In altri casi i e j possono essere aggiornati a turno (es. successivo) Notare che questo ciclo fa valori.length/2 iterazioni, ma ad ogni iterazioni vengono letti 2 valori. Totale: tutti i valori.length valori

(16)

Scansione a doppio indice di un array (4)

Altro esempio: Si supponga di avere un array valori di 10 elementi in cui gli elementi della prima met`a e della seconda met`a sono disposti in ordine crescente. Copiare tutti gli elementi di valori in un nuovo array valori2 in modo che siano tutti ordinati.

Se questo `e valori:

valori 3 6 12 66 74 1 13 15 91 100

0 1 2 3 4 5 6 7 8 9

Questo deve essere valori2:

valori2 1 3 6 12 13 15 66 74 91 100

0 1 2 3 4 5 6 7 8 9

Ideesu come fare?

(17)

Scansione a doppio indice di un array (5)

Idea: confronto valori[0] con valori[5] e copio il minore in valori2.

Incremento l’indice del valore che ho copiato, ripeto il confronto e continuo cos`ı ...

int v a l o r i 2 = new int[ 1 0 ] ;

int i =0 , j =5 , k =0; // k s e r v e per s c o r r e r e v a l o r i 2 do {

// c o p i a il m i n o r e e i n c r e m e n t a i o j if ( v a l o r i [ i ] < v a l o r i [ j ]) {

v a l o r i 2 [ k ] = v a l o r i [ i ];

i ++;

} e l s e {

v a l o r i 2 [ k ] = v a l o r i [ j ];

j ++;

}

// i n c r e m e n t a k k ++;

} w h i l e (( i < 5 ) & & ( j < 1 0 ) ) ;

// uno tra i e j non ha c o n c l u s o il suo l a v o r o ...

// s o l o uno di q u e s t i due c i c l i v i e n e e s e g u i t o w h i l e ( i <5) { v a l o r i 2 [ k ]= v a l o r i [ i ]; i ++; k ++; } w h i l e ( j < 1 0 ) { v a l o r i 2 [ k ]= v a l o r i [ j ]; j ++; k ++; }

(18)

Scansione a doppio indice di un array (6)

Schema di programma: scansione a doppio indice

1. Dichiara e inizializza due indici i e j 2. In un ciclo

usa i e j per confrontare/scambiare i valori dell’array aggiorna i e/o j

3. Gestisci eventuali elementi dell’array non considerati 4. Stampa il risultato

(19)

Scansione a doppio indice di un array (6)

Altri esempi in cui pu`o essere applicato questo schema:

1. Verificare se un array di char `e palindromo, ossia la sequenza di caratteri letti da sinistra a destra, oppure da destra a sinistra `e la stessa. (Il concetto di palindromo `e di solito riferito alle stringhe: ad es. "ailatiditalia", "itopinonavevanonipoti",

"inotipiedideipitoni",...)

(20)

Scansione di un array con cicli annidati (1)

Nello schema precedente ogni elemento dell’array veniva confrontato con un altro elemento.

Spesso capita di dover confrontare ogni elemento dell’array con tutti gli altri elementi

Esempio: Un programma che verifica se esistono due elementi uguali nell’array

Come in questo caso:

valori 7 6 12 667 -33 0 12 -34 4 100

0 1 2 3 4 5 6 7 8 9

Bisogna per forza confrontare ogni elemento con tutti gli altri

(21)

Scansione di un array con cicli annidati (2)

Idea: prendo il primo elemento e lo confronto con tutti i successivi, prendo il secondo elemento e lo confronto con tutti i successivi, ....

// f l a g che d i v e n t a t r u e q u a n d o si t r o v a un e l e m e n t o r i p e t u t o b o o l e a n t r o v a t o =f a l s e;

// per o g n i e l e m e n t o ( u l t i m o e s c l u s o ) . . . for (int i =0; i <9; i ++) {

// ... c o n s i d e r a t u t t i i s u c c e s s i v i ( da i +1) ...

for (int j = i +1; j < 1 0 ; j ++) { // ... e c o n f r o n t a

if ( v a l o r i [ i ]== v a l o r i [ j ]) t r o v a t o =t r u e; }

}

Note:

quando si considera il secondo elemento non c’e’ bisogno di confrontarlo con il primo (gi`a fatto!), e cos`ı via...

per evitare tali controlli superflui non si pu`o usare for-each (non consente di gestire gli indici)

si possono usare anche cicli whilee do-while(ad esempio, per interrompere la ricerca appena trovato diventa true)

(22)

Scansione di un array con cicli annidati (3)

Schema di programma: scansione con cicli annidati

1. Dichiara e inizializza un indice i

2. Cicla per i che va da 0 alla penultima posizione In ogni iterazione del ciclo:

a. Dichiara e inizializza un indice j

b. Cicla per j che va da i+1 all’ultima posizione In ogni iterazione del ciclo:

Usa i e j per confrontare/scambiare gli elementi 3. Stampa il risultato

(23)

Scansione di un array con cicli annidati (4)

Altro esempio: Ordinamento di un array (algoritmo Selection sort) Da cos`ı:

valori 7 6 12 667 33 10 13 34 4 100

0 1 2 3 4 5 6 7 8 9

A cos`ı:

valori 4 6 7 10 12 13 33 34 100 667

0 1 2 3 4 5 6 7 8 9

(24)

Scansione di un array con cicli annidati (5)

L’algoritmoSelection sort `e (pi`u o meno) quello che molti usano per sistemarsi le carte in mano...

(25)

Scansione di un array con cicli annidati (6)

Idea: cerco il valore minimo e lo metto in prima posizione (scambiandoli), cerco il minimo dei rimanenti e lo metto in seconda posizione

(scambiandoli), ....

Animazione: in rosso i valori da scambiare e in grassetto i valori

“sistemati”

valori 7 6 12 667 33 10 13 34 4 100

0 1 2 3 4 5 6 7 8 9

valori 4 6 12 667 33 10 13 34 7 100

0 1 2 3 4 5 6 7 8 9

valori 4 6 12 667 33 10 13 34 7 100

0 1 2 3 4 5 6 7 8 9

valori 4 6 7 667 33 10 13 34 12 100

0 1 2 3 4 5 6 7 8 9

eccetera...

(26)

Scansione di un array con cicli annidati (7)

Ecco la soluzione (Selection sort):

for (int i =0; i <9; i ++) {

// c e r c a il m i n i m o n e l l e p o s i z i o n i tra i e 1 0 . . . int p o s m i n = i ; // ... p o r t a n d o s i d i e t r o l ’ i n d i c e for (int j = i ; j < 1 0 ; j ++) {

if ( v a l o r i [ j ] < v a l o r i [ p o s m i n ]) p o s m i n = j ;

}

// s c a m b i a il m i n i m o con l ’ e l e m e n t o in p o s i z i o n e i int tmp = v a l o r i [ i ];

v a l o r i [ i ] = v a l o r i [ p o s m i n ];

v a l o r i [ p o s m i n ] = tmp ; }

Note:

La ricerca del minimo segue lo schema “scansione sequenziale”

portandosi dietro un indice posmin

Il for interno fa partire j dal valore i, non i+1 (piccolo aggiustamento dello schema “scansione con cicli annidati”)

(27)

Scansione di un array con cicli annidati (8)

Altri esempi in cui pu`o essere applicato questo schema:

1. Altri algoritmi di ordinamento iterativi (Ad esempio: Insertion sort e Bubble sort)

2. Stampare tutte le coppie possibili di valori dell’array

3. Determinare il numero di copie dell’elemento che compare pi`u volte nell’array

In tutti questi esempi il tipo dei valori dell’array pu`o essere numerico, char o String

(28)

Breve confronto tra gli schemi proposti (1)

Abbiamo visto

Scansione sequenziale Scansione a doppio indice Scansione con cicli annidati

I tre schemi servono per risolvereproblemi diversi

La “scansione sequenziale” usa un solo indice, mentre gli altri ne usano due

I due indici sono gestiti daun unico ciclonella “scansione a doppio indice”

Sono invece gestiti dadue cicli diversi nella “scansione con cicli annidati”

(29)

Breve confronto tra gli schemi proposti (2)

Nella “scansione sequenziale” e “a doppio indice” ogni elemento dell’array viene usato una volta sola (o comunque poche volte)

Nella “scansione con cicli annidati” ogni elemento pu`o essere usato fino a length volte

Questo incide sul tempo di esecuzione del programma (o meglio sul numero di operazioni che dovr`a eseguire – detto anchecomplessit`a computazionale)

Un programma che usa la “scansione sequenziale” o la “scansione a doppio indice” esegue un numero di operazioni proporzionale alla dimensione dell’array (complessit`a lineare)

Un programma che usa la “scansione con cicli annidati” esegue un numero di operazioniproporzionale al quadrato della dimensione dell’array (complessit`a quadratica)

Al crescere della dimensione dell’array, il numero di operazioni

dell’approccio “scansione con cicli annidati” cresce pi`u velocementeche

Riferimenti

Documenti correlati

Nella dichiarazione di una variabile se ne specifica il nome e il tipo (o meglio, il tipo dei valori che pu` o contenere). Nell’esempio, abbiamo dichiarato tre variabili con nomi

La guardia pu` o essere una qualunque espressione booleana Il comando (o blocco) ` e detto corpo del do-while. Semantica

Fondamenti di Informatica 1 A.A. variabili, costanti, espressioni) sono associati ad un tipo che li caratterizza..  tipo

 valore di ritorno di un metodo per definire una procedura void azzera(){x=y=z=0;}. Tipi e array in Java , Paolo

=⇒ Non serve specificare la dimensione del vettore nel parametro formale ( `e un puntatore al tipo degli elementi del vettore).. Quando passiamo una matrice ad una funzione, per

Abbiamo visto che il tipo di dato degli elementi di un array può essere qualsiasi tipo valido.. Il tipo di dato degli elementi di un array può dunque anche essere un

Il numero di figli di ogni nodo di un albero pu` o essere fiassato o variabile Quando il numero dei figli di ogni nodo ` e fissato a 2, l’albero si dice binario (come

Ogni area della schermata principale di Eclipse ` e detta Vista (View) La vista centrale ci consentira di scrivere il nostro programma La vista “Package Explorer” (a sinistra)