310 likes | 520 Views
Capitolo 6 (Deitel) I vettori. Sommario 6.1 - Introduzione 6.2 - Vettori 6.3 - Dichiarazione di vettori 6.4 - Inizializzazione di vettori 6.5 - Esempio di uso dei vettori 6.6 - Vettori di caratteri 6.7 - Passare i vettori alle funzioni 6.8 - Ordinare i vettori
E N D
Capitolo 6 (Deitel)I vettori Sommario 6.1 - Introduzione 6.2 - Vettori 6.3 - Dichiarazione di vettori 6.4 - Inizializzazione di vettori 6.5 - Esempio di uso dei vettori 6.6 - Vettori di caratteri 6.7 - Passare i vettori alle funzioni 6.8 - Ordinare i vettori 6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori 6.10 - Ricerca nei vettori: ricerca lineare e ricerca binaria 6.11 - Vettori multidimensionali
6.1 - Introduzione • Supponiamo di dover rappresentare N dati dello stesso tipo • La temperatura di ogni giorno di questo mese, o l’altezza degli studenti di questa classe, o il valore di un titolo in borsa ad ogni ora di oggi, ecc.. • Ognuno dei casi precedenti comprende un gran numero di dati omogenei • Con le conoscenze attuali, li rappresenteremmo con N variabili dello stesso tipo, ma è davvero la scelta migliore? • Fortunatamente il C offre una soluzione più adatta a questa situazione • Vettori (o array) • Costituiscono il primo tipo di dato strutturato che vedremo nel corso • Sono strutture dati statichecontenenti una serie di dati omogenei, ovvero che hanno una caratteristica che li accomuna: il tipo • Esempi: una serie di numeri, una serie di caratteri, ecc.. • Con il termine “statiche” si intende che hanno dimensione (numero di elementi) prefissata e mai variabile durante l’esecuzione del programma • In C esistono anche strutture dati dinamiche, cioè la cui dimensione può variare nel corso del programma • Verranno affrontate nei capitoli successivi
Nome del vettore (si noti che tutti gli elementi di questo vettore hanno lo stesso nome, c) c[0] -45 c[1] 6 c[2] 0 c[3] 72 c[4] 1543 c[5] -89 c[6] 0 c[7] 62 c[8] -3 c[9] 1 c[10] 6453 c[11] 78 Numero della posizione di ogni elemento all’interno del vettore c (indice) 6.2 - Vettori (1/2) • Vettore • E’ una collezione di elementi dello stesso tipo • Tale tipo individua il tipo del vettore • E’ un’unica variabile, per cui tutti suoi elementi condividono un nome comune • Tale nome individua il nome del vettore • I valori dei vari elementi del vettore vengono memorizzati in locazioni di memoria contigue • E’ una sequenza indicizzata di elementi • La cui dimensione è fissata e nota a priori • Per accedere ad un elemento, si deve specificare il nome del vettore e il numero la sua posizione • Sintassi: nome_vettore[indice] • Nell’esempio, contiene N elementi di nome c: • c[0], c[1]...c[n-1] • Il primo elemento ha indice/posizione 0 • L’i-esimo elemento ha indice/posizione i-1 • L’ultimo elemento ha indice/posizione n-1
6.2 - Vettori (2/2) • Ogni elemento di un vettore va trattato come una qualsiasi variabile dello stesso tipo • Sia per le operazioni di assegnamento di valori all’elemento, sia per le operazioni che usano l’elemento per effettuare calcoli o stampa a video c[0] = 3; printf( "%d", c[0] ); printf( "%d", c[0] + c[1] + c[2] ); x = c[2] / 2; • Nell’accesso ad un elemento, l’indice può essere dato da una variabile precedentemente assegnata o perfino da un’espressione • In tal si prende l’elemento in posizione pari al valore corrente della variabile o al risultato dell’espressione • Se x=3, allora c[5-2] == c[3] == c[x] • Se a=5e b=6, allora c[a+b]++ incrementa il 12° elemento del vettore c
6.3 - Dichiarazione di vettori • Un vettore viene dichiarato specificando: • Il nome dell’array, condiviso da tutti i suoi elementi • Il tipo del vettore, condiviso da tutti i suoi elementi • Il numero degli elementi contenuti (dimensione dell’array) Tipo_vettore Nome_vettore[Numero_elementi]; • Esempi: int c[ 10 ]; float MyArray[ 3284 ]; • Si noti che il C obbliga a specificare esplicitamente la dimensione (statica) del vettore in fase di dichiarazione • Non farlo comporta la generazione di un errore in compilazione • La dimensione è data da un numero o da una costante (#define..) • Per dichiarare insieme più vettori dello stesso tipo • Si usa la stessa sintassi valida per ogni altra variabile semplice int b[ 100 ], x[ 27 ];
6.4 - Inizializzazione di vettori • In fase di dichiarazione, un vettore può essere inizializzato • I suoi valori iniziali vanno specificati tra { } e separati da virgole int n[5] = {1, 2, 3, 4, 5 }; • Se non ci sono abbastanza inizializzatori rispetto alla dimensione indicata esplicitamente, gli elementi più a destra sono inizializzati a 0 • Se invece ce ne sono troppi, si genera un errore di sintassi • Solo quando si unisce dichiarazione e inizializzazione • Si può omettere la dimensione del vettore, in quanto automaticamente determinata in base al numero di inizializzatori • Nel caso di int n[] = { 1, 2, 3, 4, 5 };ho 5 inizializzatori, perciò la dimensione del vettore viene fissata a 5 elementi • Il C non ha meccanismi di controllo sui limiti dei vettori • Dato un vettore di dimensione N, quando si accede ad una posizione superiore a (N-1) si ha un errore logico, non rilevato dal compilatore • Farlo può portare ad errori di indirizzamento (memory fault) o “sporcare” altre variabili in memoria, rendendo così l’errore difficile da localizzare • E’ compito del programmatore fare in modo di non eccedere tali limiti
1 /* Fig. 6.8: fig06_08.c - Visualizzazione di istogrammi */ 2 #include <stdio.h> 3 #define SIZE 7 4 5 int main(){ 6 int n[ SIZE ] = { 19, 3, 15, 7, 11, 9, 13 }; 7 int i, j; 8 9 printf( "%s%13s%17s\n", "Elemento", "Valore", “Istogramma" ); 10 for ( i = 0; i <= SIZE - 1; i++ ) { 11 printf( "%8d%13d ", i, n[ i ]) ; 12 for ( j = 1; j <= n[ i ]; j++ ) printf( "%c", '*' ); 13 printf( "\n" ); 14 } 15 return 0; 16 } 6.5 - Esempio di uso dei vettori • Inizializza • il vettore • 2.Ciclo per la • stampa di • righe/colonne • Visualizzazione • del programma Elemento Valore Istogramma 0 19 ******************* 1 3 *** 2 15 *************** 3 7 ******* 4 11 *********** 5 9 ********* 6 13 *************
6.6 - Vettori di caratteri (1/4) • Vettori di caratteri (stringhe) • La stringa “first" può essere implementata come vettore di caratteri • In tal caso ogni stringa di N lettere si traduce in un vettore di (N+1) caratteri • N+1 perchè il C obbliga a terminare ogni stringa con il carattere nullo ‘\0’, che occuperà quindi l’ultima cella del vettore • Ogni vettore di caratteri può essere inizializzato con una stringa posta tra doppi apici o dalla sequenza di caratteri tra { }, a patto che l’ultimo sia \0 char string1[] = “first"; char string1[] = { 'f', 'i', 'r', 's', 't', '\0' }; • Il vettore string1 ha quindi effettivamente 6 elementi • Nel primo caso, il carattere nullo è aggiunto a fine vettore automaticamente • Lo stesso avviene se il vettore è inizializzato da una scanf con formato %s • L’unico modo per inizializzarlo con la sequenza di caratteri omettendo il carattere nullo in coda è dare la dimensione del vettore esplicitamente char string1[6] = { 'f', 'i', 'r', 's', 't' }; • Anche in questo caso il carattere nullo è aggiunto in coda automaticamente • Per evitare errori, si dà una dimensione maggiore del numero di caratteri
6.6 - Vettori di caratteri (2/4) • Si può usare un vettore di N caratteri per memorizzare anche stringhe più corte di N-1 caratteri • Così facendo le celle dopo quella contenente il carattere nullo sono concettualmente vuote e di fatto contengono valori casuali (senza senso) • Mettere il carattere nullo permette di individuare la parte utile della stringa • Acquisizione di una stringa in input scanf( "%s", string2 ) ; • Il nome del vettore rappresenta l' indirizzo in memoria del vettore, per cui la & non è necessaria nell scanf • Vengono acquisiti tutti i caratteri finchè si incontra il primo spazio bianco • Tutto quello che scrivo dopo lo spazio viene inesorabilmente perso • Per acquisire frasi, servono altri metodi (es. più scanf in sequenza) • Non essendoci controllo sui limiti, si deve fare attenzione anche qui • Non scrivere oltre la fine dichiarata del vettore (causa errori logici) • Se invece la stringa è acquisita con un ciclo carattere per carattere • Attenzione che quando si preme invio, anch’esso è acquisito come carattere \n
6.6 - Vettori di caratteri (3/4) • Stampa della stringa • La si può stampare con un’unica printf con formato %s • printf(“%s”,string1) che stampa tutti i caratteri fino a quello nullo • Oppure la si stampa carattere per carattere, con un ciclo a sentinella avente flag pari ovviamente al carattere nullo • Ad esempio printf (“%c”,string1[3]) stamperà il carattere 's' • Gli errori logici più comuni (non rilevati dal compilatore): • Inizializzare la stringa omettendo sia la dimensione del vettore che il carattere nullo di chiusura • Se la stampo con %s, ottengo una stringa diversa da quella desiderata • Se la stampo con il ciclo controllato da sentinella vado in loop infinito • Inizializzare la stringa omettendo il carattere nullo di chiusura e mettendo una dimensione pari al numero di inizializzatori (escluso il carattere nullo) • Se la stampo con %s, ottengo una stringa diversa da quella voluta • Se la stampo con il ciclo a sentinella vado in loop infinito • Stampare i caratteri con indice che è oltre la dimensione del vettore • Stampa caratteri casuali senza senso, anche se era stato messo il carattere nullo
1 /* Fig. 6.10: fig06_10.c 2 Trattare un vettore di caratteri come una stringa */ 3 #include <stdio.h> 4 5 int main(){ 6 char stringa1[ 20 ], stringa2[] = "stringa letterale"; 7 int i; 8 9 printf(" Inserire una stringa: "); 10 scanf( "%s", stringa1 ); 11 printf( “La prima stringa è: %s\nLa seconda stringa è: %s\n 12 “La prima con gli spazi è:\n", stringa1, stringa2 ); 13 for ( i = 0; stringa1[ i ] != '\0'; i++ ) 14 printf( "%c ", stringa1[ i ] ); 15 printf( "\n" ); 16 return 0; 17 } 6.6 - Vettori di caratteri (4/4) 1. Inizializza i vettori di caratteri 2. Acquisisce la stringa 3. Stampa i vettori come stringhe, direttamente 4. Ciclo per la stampa carattere per carattere inserendo degli spazi tra ogni carattere Visualizzazione del programma Inserire una stringa: Ciao a tutti La prima stringa è: Ciao La seconda stringa è: stringa letterale La prima con gli spazi è: C i a o
6.7 - Passare i vettori alle funzioni (1/4) • Passare i vettori come parametri di funzioni • In C, il metodo di default di passaggio dei parametri è per valore • Dentro la funzione si usa/modifica una copia locale della variabile passata • I vettori fanno eccezione, sono passati automaticamente per riferimento • Si passa il loro vero indirizzo e non una copia del loro contenuto • Modifiche del vettore nella funzione si riflettono anche all’esterno perché vanno a modificare le locazioni di memoria originali dell’array • Il nome del vettore rappresenta l’indirizzo in memoria del primo elemento • Quindi la funzione sa sempre dove il vettore è memorizzato • Essendo ogni vettore costituito da celle contigue, basta conoscere la posizione della prima perché siano note le posizioni di tutti i suoi elementi • Sintassi: si specifica il nome del vettore senza parentesi int MyArray[ 24 ]; MyFunction(MyArray, 24 ); • Di solito, alla funzione si passa anche la dimensione del vettore • Va passata la dimensione se nel prototipo/definizione è richiesta • E’ richiesta quando viene usata dentro la funzione (in pratica quasi sempre)
6.7 - Passare i vettori alle funzioni (2/4) • Esiste un modo per passare un intero vettore per valore • Si deve anteporre parola chiave const al tipo del parametro presente nella definizione della funzione • Passare gli elementi dei vettori come parametri di funzioni • Gli elementi sono invece passati per valore, come qualsiasi altra variabile • Ancora una volta, la funzione lavora su una copia dell’elemento originale • Le modifiche sul parametro dentro la funzione non hanno effetto sull’originale • Sintassi: MyFunction2(MyArray[3]); • Sintassi nel prototipo della funzione funzione void ModifyArrays(int b[], int DimensioneVettore); • Il nome del vettore va seguito da [] proprio per indicare che è un vettore • Nel prototipo, come al solito si possono omettere i nomi dei parametri • int b[]potrebbe semplicemente essereint [] • int DimensioneVettore potrebbe semplicemente essere int • Nella definizione, come al solito invece i nomi dei parametri vanno messi
1 /* Fig. 6.13: fig06_13.c - Passare alle funzioni vettori/elementi */ 2 #include <stdio.h> 3 #define SIZE 5 4 5 void modificaVettore( int [], int ); L’intero vettore passato per chiamata per riferimento e può essere modificato 6 void modificaElemento( int ); 7 8 int main(){ L’elemento del vettore passato attraverso una chiamata per valore e non può essere modificato 9 int a[ SIZE ] = { 0, 1, 2, 3, 4 }, i; 10 11 printf( "Effetti del passare un intero vettore per riferimento:" 12 "\n\nI valori del vettore originale sono:\n" ); 13 for ( i = 0; i <= SIZE - 1; i++ ) printf( "%3d", a[ i ] ); 14 printf( "\n" ); 15 modificaVettore( a, SIZE ); /* passaggio per riferimento */ 16 printf( “I valori del vettore modificato sono:\n" ); 17 for ( i = 0; i <= SIZE - 1; i++ ) 18 printf( "%3d", a[ i ] ); 19 printf( "\n\n\nEffetti del passare un elemento di un vettore " 20 “per valore:\n\nIl valore di a[3] è %d\n", a[ 3 ] ); 21 modificaElemento( a[ 3 ] ); /* passaggio per valore */ 22 printf( “Il valore di a[ 3 ] è %d\n", a[ 3 ] ); 23 return 0; 24 } 6.7 - Passare i vettori alle funzioni (3/4) • Dichiarazione • delle funzioni • 2.Passa il vettore • ad una funzione • 3.Passa un elemento • ad una funzione
25 26 void modificaVettore( int b[], int size ){ 27 int j; 28 29 for ( j = 0; j <= size - 1; j++ ) b[ j ] *= 2; 30 } 31 32 void modificaElemento( int e ){ 33 printf( “Il valore in modifyElement è %d\n", e *= 2 ); 34 } 6.7 - Passare i vettori alle funzioni (4/4) 4.Definizioni delle funzioni Visualizzazione del programma Effetti del passare un intero vettore per riferimento: I valori del vettore originale sono: 0 1 2 3 4 I valori del vettore modificato sono: 0 2 4 6 8 Effetti del passare un elemento di un vettore per valore: Il valore di a[3] è 6 Il valore in modificaElemento è 12 Il valore di a[3] è 6
6.8 - Ordinare i vettori • L’ordinamento di dati • E’ un’operazione molto importante e frequente nelle applicazioni • Molto spesso le organizzazione devono ordinare dati • E in genere devono ordinare grosse quantità di dati • Esistono molti algoritmi di ordinamento dei dati, ma ne vedremo uno solo • Bubble Sort (ordinamento a bolle) • E’ un algoritmo di ordinamento che effettua numerose passate del vettore • Passata significa scansione dell’intero vettore con accesso ad ogni elemento • Alla fine di ogni passata si otterrà un ordinamento parziale intermedio • Ad ogni passata, si confrontano coppie successive di elementi • Se i 2 dati sono già in ordine (o sono uguali), non si attua nessun cambiamento • Se non sono in ordine, i 2 elementi vengono scambiati • Esempio (ordinamento crescente): Vettore originale: 3 4 2 6 7 Passata 1: 3 2 4 6 7 Ha scambiato la coppia (4,2) Passata 2: 2 3 4 6 7 Ha scambiato la coppia (3,2) • Gli elementi più piccoli/leggeri pian piano emergono (scendono di posizione) • Su N dati, fa sempre N-1confronti ad ogni passata e in totale N-1passate • Se il vettore è già ordinato con meno di N-1 passate, le fa tutte comunque
6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (1/7) • Media: è il valor medio calcolato su una serie di dati • Si ottiene dalla somma degli elementi del vettore diviso il numero di elementi • 1, 2, 3, 4, 5, 6 , 7, 8, 9 La media su questi dati è 5 • Mediana: è il numero nel mezzo di una sequenza ordinata • Si ordina il vettore e si prende l’elemento in posizione centrale (dimensione/2) • 1, 2, 3, 4, 5 La mediana su questi dati è 3 • Moda: è il numero che ricorre più frequentemente nella serie • 1, 1, 1, 2, 3, 3, 4, 5 La moda su questi dati è 1
1 /* Fig. 6.16: fig06_16.c - Calcola media, mediana e moda dei dati */ 2 #include <stdio.h> 3 #define SIZE 99 4 5 void trovaMedia( constint [] ); 6 void trovaMediana( int [] ); 7 void trovaModa( int [], constint [] ) ; 8 void bubbleSort( int [] ); 9 void stampaVettore( constint [] ); 10 11 int main(){ 12 int frequenze[10] = { 0 }; 13 int vettoreDati[SIZE] = 14 { 6, 7, 8, 9, 8, 7, 8, 9, 8, 9, 7, 8, 9, 5, 9, 8, 7, 8, 7, 8, 15 6, 7, 8, 9, 3, 9, 8, 7, 8, 7, 7, 8, 9, 8, 9, 8, 9, 7, 8, 9, 16 6, 7, 8, 7, 8, 7, 9, 8, 9, 2, 7, 8, 9, 8, 9, 8, 9, 7, 5, 3, 17 5, 6, 7, 2, 5, 3, 9, 4, 6, 4, 7, 8, 9, 6, 8, 7, 8, 9, 7, 8, 18 7, 4, 4, 2, 5, 3, 8, 7, 5, 6, 4, 5, 6, 1, 6, 5, 7, 8, 7 }; 19 20 trovaMedia( vettoreDati ); 21 trovaMediana( vettoreDati ); 22 trovaModa( frequenze, vettoreDati ); 23 return 0; 24 } 6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (2/7) 1. Prototipi delle funzioni 2. Inizializza i vettori 3. Chiama le funzioni per il calcolo di media, mediana e moda
25 26 void trovaMedia( constint vettore[] ){ 27 int j, totale = 0; 28 29 printf( "%s\n%s\n", "Media", "********" ); 30 for ( j=0; j<=SIZE-1; j++ ) totale += vettore[j]; 31 printf( “La media è uguale alla somma totale degli elementi" 32 “\ndiviso per il numero di elementi ( %d ).\n" 33 “Qui la media vale: %d / %d = %.4f\n\n“, 34 SIZE, totale, SIZE, (double) totale / SIZE ); 35 } 47 } 48 36 37 void trovaMediana( int vettore[] ){ 38 printf( "\n%s\n%s\n%s", "Mediana", "********", 39 “Il vettore con i dati non ordinati è:" ); 40 stampaVettore( vettore ); 41 bubbleSort( vettore ); 42 printf( "\n\nIl vettore ordinato è:" ); 43 stampaVettore( vettore ); 44 printf( "\n\nLa mediana è l’elemento %d del vettore " 45 "ordinato.\nQui la mediana vale: %d\n\n", 46 SIZE / 2, SIZE, vettore[SIZE/2] ); 6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (3/7) • 4. Definizione della funzione • che calcola la media • 5. Calcolo della media • 6. Stampa della media • 7. Definizione della funzione • che calcola la mediana • 8. Chiama la funzione che • stampa l’array originale • 9. Chiama la funzione che • ordina l’array • 10. Chiama la funzione che • stampa l’array ordinato • 11. Visualizza l’elemento in posizione SIZE/2
66 printf( "\n" ); 67 } Da notare che l’elemento di freq[]è sempre un valore di un elemento divettore[] 49 void trovaModa( int freq[], constint vettore[] ){ 68 printf( “La moda è l’elemento più ricorrente nel vettore.\n" 50 int dato, j, h, maxFreq = 0, moda = 0; 69 “Qui la moda è %d che nel vettore è presente ben" 51 70 " %d volte.\n", moda, maxFreq ); 52 printf( "%s\n%s\n", "Moda", "********" ); 71 } 53 for ( dato=1; dato<=9; dato++ ) freq[dato] = 0; La stampa degli asterischi dipende dal valore di freq[] 54 for ( j=0; j<=SIZE-1; j++ ) ++freq[ vettore[j] ]; 55 printf( "%s%11s%19s\n\n%54s\n%54s\n\n", 56 “Elemento", "Frequenza", “Istogramma", 57 "1 1 2 2", "5 0 5 0 5" ); 58 for ( dato=1; dato<=9; dato++ ){ 59 printf( "%8d%11d ", dato, freq[dato] ); 60 if ( freq[dato] > maxFreq ){ 61 maxFreq = freq[dato]; 62 moda = dato; 63 } 64 for ( h=1; h<=freq[dato]; h++ ) 65 printf( "*" ); 6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (4/7) 12. Definizione della funzione che calcola la moda 13. Ciclo di incremento dei contatori delle occorrenze, che son dati dagli elementi del vettore delle frequenze 14. Ad ogni giro incrementa il contatore che si trova in posizione pari al dato preso dal vettore 15. Stampa un istogramma con gli asterischi che indicano il numero di occorrenze di ogni dato 16. Funziona perchè si usa l’array delle frequenze dalla seconda posizione in poi, saltando l’indice 0
90 printf( "%2d", vettore[ j ] ); 91 } 73 void bubbleSort( int vettore[] ){ Bubble sort: se gli elementi sono fuori ordine, li scambia. 92 } 72 74 int pass, j, temp; 75 76 for ( pass=1; pass<=SIZE-1; pass++ ) 77 for ( j=0; j<=SIZE-2; j++ ) 78 if ( vettore[ j ] > vettore[ j + 1 ] ){ 79 temp = vettore[ j ]; 80 vettore[ j ] = vettore[ j + 1 ]; 81 vettore[ j + 1 ] = temp; 82 } 83 } 84 85 void stampaVettore( constint vettore[] ){ 86 int j; 87 88 for ( j=0; j<=SIZE-1; j++ ){ 89 if ( j % 20 == 0 ) printf( "\n" ); 6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (5/7) • 17. Definizione della funzione • che ordina il vettore • Ciclo per fare le SIZE-1 • passate del vettore • Ciclo interno per fare i • SIZE-1 confronti per ogni • passata del vettore • Usa una variabile apposta • per salvare uno dei due • valori da scambiare, in • modo da non perderlo • nello scambio • 20. Definizione della funzione • che stampa il vettore
6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (6/7) Visualizzazione del programma Media ******** La media è uguale alla somma totale degli elementi diviso per il numero di elementi (99). Qui la media vale: 681 / 99 = 6.8788 Mediana ******** Il vettore con i dati non ordinati è: 7 8 9 8 7 8 9 8 9 7 8 9 5 9 8 7 8 7 8 6 7 8 9 3 9 8 7 8 7 7 8 9 8 9 8 9 7 8 9 6 7 8 7 8 7 9 8 9 2 7 8 9 8 9 8 9 7 5 3 5 6 7 2 5 3 9 4 6 4 7 8 9 6 8 7 8 9 7 8 7 4 4 2 5 3 8 7 5 6 4 5 6 1 6 5 7 8 7 Il vettore ordinato è: 1 2 2 2 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 La mediana è l’elemento 49 del vettore ordinato. Qui la mediana vale: 7
6.9 - Caso di studio: calcolare media, mediana e moda usando i vettori (7/7) Visualizzazione del programma Mode ******** Elemento Frequenza Istogramma 1 1 2 2 5 0 5 0 5 1 1 * 2 3 *** 3 4 **** 4 5 ***** 5 8 ******** 6 9 ********* 7 23 *********************** 8 27 *************************** 9 19 ******************* La moda è l’elemento più ricorrente nel vettore. Qui la moda è 8 che nel vettore è presente ben 27 volte.
6.10 - Ricerca nei vettori: ricercalineare e ricerca binaria (1/2) • Cercare un valore chiave in un vettore • Si può trovare il valore chiave con algoritmi di ricerca lineare o binaria • Ricerca lineare • Scandisce tutto il vettore confrontando ogni elemento col valore chiave • Prosegue la scansione e fa confronti finchè non trova il valore chiave • E’ un algoritmo molto semplice, utile per vettori piccoli e disordinati • Ha complessità lineare, ovvero nel caso peggiore richiede N confronti, su un vettore di N elmenenti • Ricerca binaria • E’ un algoritmo utilizzabile solo su vettori già ordinati • Si confronta l’elemento di mezzo (posizione N/2) del vettore con la chiave • Se sono uguali, allora il valore voluto è stato trovato • Se chiave < mezzo, cerca allo stesso modo nella sola prima metà del vettore • Se chiave > mezzo, cerca allo stesso modo nella sola seconda metà del vettore • Si continua a ripetere questa strategia su vettori man mano sempre più piccoli con la certezza che il valore chiave non è mai nelle parti di vettore scartate • Molto veloce, fa al massimo P passi, dove P è l’intero superiore a log (N) • Per un vettore di 30 elementi servono al massimo 5 passi, perchè 5 > log (30) 2 2
1 int RicercaLineare( const int vettore[], int chiave, int size ){ 1 int ricercaBinaria( constint vettore[], int chiave, int size ){ 2 int posMin = 0, posMax = size-1, posMedia; 3 while (posMin <= posMax ){ /* Ad ogni giro, l’array è ridotto */ 4 posMedia = (posMin + posMax ) / 2; 5 if ( vettore[posMedia] == chiave ) return posMedia;/* Trovato! */ 6 else if ( vettore[posMedia] > chiave ) posMax = posMedia - 1; 7 else posMin = posMedia + 1; 8 } /* Ritorna la posizione del valore trovato */ 10 } 3 for (i=0; i<size; i++ ){ 2 int i; 4 if ( vettore[i] == chiave ) return i; /* Trovato! */ 5 } /* Ritorna la posizione del valore trovato */ 6 return -1; /* Valore chiave non trovato */ 9 return -1; /* Valore chiave non trovato */ 7 } 6.10 - Ricerca nei vettori: ricercalineare e ricerca binaria (2/2) • Funzione di ricerca lineare • Funzione di ricerca binaria (avendo l’array già ordinato)
Colonna 0 Colonna 1 Colonna 2 Colonna 3 a[2][0] a[0][0] a[1][3] a[2][3] a[0][1] a[1][1] a[0][2] a[1][2] a[2][2] a[0][3] a[1][0] a[2][1] Riga 0 Riga 1 Riga 2 6.11 - Vettori multidimensionali (1/6) • Vettori multidimensionali • Implementano tabelle con righe e colonne (vettore m per n ) • Si accede agli elementi specificando indice di riga e di colonna (matrici) printf( "%d", b[ 0 ][ 1 ] ); • Per il resto, i loro elementi vanno trattati come quelli di normali vettori • Si può anche ricavare l’array monodimensionale di una riga della matrice int b[] = a[1]; Ora b contiene i valori in a[1][0], a[1][1], a[1][2], a[1][3] • Inizializzazione int c[ 2 ][ 2 ] = { { 1, 2 }, { 3, 4 } }; • Gli inizializzatori sono raggruppati per riga tra { } più interne • Tutti gli elementi non inizializzati assumono valore 0 come al solito int c[ 2 ][ 2 ] = { { 1 }, { 3, 4 } };
6.11 - Vettori multidimensionali (2/6) • Passare le matrici come parametri • Nel prototipo e nella definizione di funzioni, si deve sempre specificare la dimensione relativa alle colonne in modo esplicito int funzione1( int [][ SIZE ], int, int ); int funzione1( int matrice1[ ][ SIZE ], int righe, int colonne){ …. } • Come per i normali vettori, la matrice è passata di default per riferimento • Se si vuole passare la matrice per valore, si deve usare const int funzione1( const int [][ SIZE ], int, int ); • Si può passare anche un’intera riga di una matrice, mai una colonna funzione( matrice[ riga ], SIZE ); • Esempio d’uso classico: i menu testuali char menuOperazioni [4][50]={ {"1) Carica array con numeri casuali"}, {"2) Ricerca del massimo"}, {"3) Calcola la media"}, {"0) Esci dal programma"} }; • Attenzione ai limiti del vettore, la dimensione delle colonne deve essere sufficiente a contenere la stringa più lunga del menu
1 /* Fig. 6.22: fig06_22.c - Esempio di matrice */ 2 #include <stdio.h> 3 #define STUDENTI 3 4 #define ESAMI 4 5 6 int minimo( constint [][ ESAMI ], int, int ); 7 int massimo( constint [][ ESAMI ], int, int ); 8 double media( constint [], int ); 9 void stampaArray( constint [][ ESAMI ], int, int ); 10 Ciascuna riga è un particolare studente e ogni colonna dà i suoi voti negli esami 11 int main(){ 13 int studente; 14 constint votiStudenti[ STUDENTI ][ ESAMI ] = 15 { { 77,68,86,73 }, { 96,87,89,78 }, { 70,90,86,81 } }; 16 17 printf( “Il vettore dei voti è:\n" ); 18 printArray( votiStudenti, STUDENTI, ESAMI ); 19 printf( "\n\nIl voto più basso è: %d\nIl voto più alto è: %d\n", 20 minimo( votiStudenti, STUDENTI, ESAMI ), 21 massimo( votiStudenti, STUDENTI, ESAMI ) ); 22 for ( studente=0; studente<=STUDENTI-1; studente++ ) 23 printf( “Il voto medio per lo studente %d è %.2f\n", 24 studente, media(votiStudenti[studente], ESAMI ) ); 25 return 0; 26 } 6.11 - Vettori multidimensionali (3/6) • 1. Prototipi delle funzioni • 2. Inizializzazione del • vettore bidimensionale • 3. Chiama la funzione • che stampa la matrice • 4. Stampa il voto più alto • e il più basso tra tutti • gli esami/studenti • chiamando le funzioni • per cercare tali voti • 5. Stampa la media degli • studenti chiamando la • funzione che le calcola
27 28 /* Cerca il voto minimo nel vettore */ 29 int minimo( constint voti[][ESAMI], int alunni, int risultati ){ 30 int i, j, votoMinimo = 100; 31 32 for ( i=0; i<=alunni-1; i++ ) 33 for ( j=0; j<=risultati-1; j++ ) 34 if ( voti[i][j] < votoMinimo ) votoMinimo = voti[i][j]; 35 return votoMinimo; 36 } 37 38 /* Cerca il voto massimo */ 39 int massimo( constint voti[][ESAMI], int alunni, int risultati ){ 40 int i, j, votoMassimo = 0; 41 42 for ( i=0; i<=alunni-1; i++ ) 43 for ( j=0; j<=risultati-1; j++ ) 44 if ( voti[i][j] > votoMassimo ) 45 votoMassimo = voti[i][j]; 46 return votoMassimo; 47 } 48 6.11 - Vettori multidimensionali (4/6) 6. Scandisce la matrice e se trova un valore più piccolo del minimo corrente questo diventa il nuovo valore minimo 7. Scandisce la matrice e se trova un valore più grande del massimo corrente questo diventa il nuovo valore massimo
51 int i, totale = 0; 52 53 for ( i=0; i<=risultati-1; i++ ) totale += voti[i]; 54 return (double) totale / risultati; 55 } 56 57 /* Visualizza questo vettore */ 58 void stampaArray(constint voti[][ESAMI], int alunni, int risultati){ 59 int i, j; 60 61 printf( “ [0] [1] [2] [3]" ); 62 for ( i=0; i<=alunni-1; i++ ){ 63 printf( "\nVOTI[%d] ", i ); 64 for ( j=0; j<=risultati-1; j++ ) printf( "%-5d", voti[i][j] ); 65 } 66 } 49 /* Determina il voto medio per un particolare studente */ 50 double media(constint voti[], int risultati){ 6.11 - Vettori multidimensionali (5/6) 8. Scandisce il vettore passato che contiene un riga della matrice (quindi i soli voti di un certo studente) per calcolarne la media 9. Ciclo che stampa a video la matrice dei voti di ogni studente
6.11 - Vettori multidimensionali (6/6) Visualizzazione del programma Il vettore dei voti è: [0] [1] [2] [3] VOTI[0] 77 68 86 73 VOTI[1] 96 87 89 78 VOTI[2] 70 90 86 81 Il voto più basso è: 68 Il voto più alto è: 96 La media dei voti per lo studente 0 è 76.00 La media dei voti per lo studente 1 è 87.50 La media dei voti per lo studente 2 è 81.75