Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
1
Strutture dati elementari
Parte 6 Vettori e ricerca binaria Matrici e triangolo di Tartaglia Records (cenni) Corso A: Prof. Stefano Berardi Corso B: Prof. Ugo de’ Liguoro
2
“Un quadrato magico di numeri”
Albert Durer. Melencolia,1514 (dettaglio) 16 3 2 13 5 10 11 8 9 6 7 12 4 15 14 1
3
Indice Parte 6: i Vettori
Strutture dati: i vettori. Esempi elementari: stampa, somma, test di uguaglianza, inversione per vettori. Esempi più complessi: ricerca lineare e binaria per vettori. Matrici: il triangolo di Tartaglia. Records e vettori parzialmente riempiti (cenni).
4
1. Strutture dati: I Vettori
In generale, le strutture dati sono un modo per rappresentare insiemi di informazioni nella memoria di un computer Una semplice variabile è un caso banale di una struttura dati, un modo per rappresentate una singola informazione. In questa parte del corso studieremo strutture dati per rappresentare insiemi di dati di tipo omogeneo, i vettori e le matrici, e per rappresentare dati di tipo eterogeneo, i record.
5
Vettori (o “array”) in C++
Un vettore v (array) è una sequenza di n oggetti tutti del medesimo tipo, detti elementi del vettore, per qualche n>0 detto la dimensione del vettore. Gli elementi del vettore sono indicizzati utilizzando interi positivi, da 0 fino a n- 1, immaginati disposti come segue: v[0], v[1], … , v[n-1]
6
Notazioni per i vettori
Le notazioni che seguono NON sono codice C/C++, ma sono la notazione che usiamo quando parliamo dei vettori: i..j = {kZ| i k j} intervallo di interi v[i..j] = {v[i], v[i+1], … , v[j]} Quindi, se i > j allora i..j = lista vuota; se un vettore v ha n elementi questi formano l’insieme v[0..n-1].
7
I vettori nella memoria RAM
Gli elementi di un vettore occupano spazi di memoria consecutivi nella memoria RAM della macchina di Von Neumann. L’indirizzo &v[i] di ogni elemento si calcola dunque con la formula: &v[i] = &v[0] + i×d, dove d = sizeof (tipo di v[]) d = dimensione di ogni elemento (es.: 4 bytes) &v[i] = indirizzo v[i] = b+i×d v[i] indirizzo b+i*d v v[0] ind. b v[1] ind. b+d v[2] ind. b+2d b = indirizzo base = &v[0] =indirizzo v[0] (es.:byte n. 1 milione) i = indice di v[i] (detto anche “spiazzamento” ). Es.: i=100, indirizzo di v[i] =
8
Vettori: dichiarazione
Un vettore v in C++ è una costante di tipo indirizzo. Viene identificato con &v[0], l’indirizzo del suo primo elemento. La dichiarazione di v consiste nell’indicazione del nome e del tipo degli elementi del vettore, e nell’indicazione del loro numero, detto la dimensione del vettore. Con sizeof(v) si indica invece il numero di bytes occupati dal vettore: 100 = numero degli elementi, o dimensione di v Invece: sizeof(v) = 100*sizeof(int) = 400 int v[100]; Tipo degli elementi Nome del vettore: v vale &v[0]
9
Vettori: l’errore più comune
La dimensione di un vettore deve essere una costante o una variabile già assegnata. Quindi le seguenti righe sono errate (ma purtroppo il compilatore non lo segnala!): int dim; double w[dim]; /* ERRORE: la variabile dim, per il solo fatto di essere dichiarata, ha un valore, ma non si può prevedere quale. Quindi si crea un vettore di dimensione “casuale”, a volte di miliardi di elementi, producendo in quest’ultimo caso un “crash” di programma */
10
Accesso agli elementi di un vettore
Per accedere ai singoli elementi di un vettore si usano gli indici: attenti a non confondere gli indici con la dimensione che compare nella dichiarazione. Gli interi tra [ ] hanno diverso significato in una dichiarazione e in una assegnazione: nella dichiarazione, 100 è la dimensione, nell’assegnazione, 0 è un indice int v[100]; /* dichiarazione */ v[0] = 6; /* assegnazione, accesso in scrittura */ int n = v[0]; /* assegnazione, accesso in lettura */
11
Inizializzazione attraverso un ciclo
Il programma che segue inizializza a 0 tutti gli elementi del vettore v: i dichiarato entro il for esisterà soltanto entro il for int v[100]; for (int i = 0; i < 100; i++) v[i] = 0; Nell’esecuzione del for, i assumerà tutti i valori tra 0 e 99 Prima dell’inizializzazione, tutti gli elementi di v, avendo un indirizzo di memoria, hanno comunque un valore, ma un valore “casuale”: provate a stamparli.
12
Inizializzazione attraverso una dichiazione
Il C++ consente di definire (quindi anche di inizializzare) un vettore elencandone gli elementi. Non è necessario indicare il numero degli elementi, che viene calcolato: double a[] = {22.2, 44.4, 66.6}; // alloca un vettore a di 3 float con // a[0] = 22.2, a[1] = 44.4, a[2] = 66.6 Guardate l’esempio 6.3 del testo di Hubbard: spiega che la dimensione di a si calcola con la formula sizeof(a)/sizeof(double)
13
Attenti a non uscire dai limiti di un vettore
Se un vettore ha dimensione d ed i<0, oppure i d, allora v[i] non dovrebbe essere definito. Invece, in C/C++, v[i] esiste sempre, è per definizione il contenuto dell’indirizzo di memoria calcolato dalla formula: &v[0] + i × sizeof (tipo di v[]) ossia un valore a caso!! Questa convenzione è introdotta per semplicità di calcolo. Il compilatore non ci avvisa quando utilizziamo un v[i] con i<0, oppure i d, sta a noi evitare che accada. Questo non accade in PASCAL: vedi Hubbard paragrafo 6.4
14
2. Alcuni semplici esempi: stampa di un vettore
La stampa di un vettore deve avvenire “elemento per elemento” (dunque usando ad es. un ciclo for): int v[100]; for (int i = 0; i < 100; i++) cout << v[i]; Se si scrive invece: cout << v; dato che v è identificato con l’indirizzo di v[0] si stampa l’indirizzo di v[0] (in esadecimale)
15
Somma e media di un array di numeri
Anche la somma di un vettore deve avvenire “elemento per elemento” (dunque usando ad es. un ciclo for): double v[100]; double somma = 0; for (int i = 0; i < 100; i++) somma = somma + v[i]; double media = somma/100.0; /*dividiamo per un numero reale per evitare l’arrotondamento*/ Per tutte le sommatorie di cui non si conosca a priori nemmeno un termine, il valore iniziale dell’accumulatore è 0, l’elemento neutro della somma
16
Un test di uguaglianza errato
Se applichiamo il test == a due vettori distinti otteniamo risposta costantemente uguale a false: int v[100], w[100]; if (v == w) … /* v, w sono identificati con gli indirizzi dei loro primi elementi, dunque il test == confronta questi ultimi. Dato che v, w sono “allocati” in posizioni diverse della memoria, i loro primi elementi hanno diversi indirizzi, anche quando v, w hanno elementi di valore uguale. Dunque v==w vale sempre false. */
17
Un test di uguaglianza corretto
Per decidere se due array di egual tipo e egual dimensione N hanno valori uguali per indici uguali, si devono confrontare tutti gli elementi usando un’iterazione. Ecco una soluzione con un WHILE: /* Il ciclo while trasporta il contatore i al primo indice per cui v[i]!=w[i], se ne esiste uno, altrimenti trasporta i fino ad N */ int i = 0; while (i < N && v[i] == w[i]) i++; if (i == N) cout << "v,w hanno elementi uguali per indici uguali"; else /* i < N */ cout << "v, w hanno diverso l’elemento di posto" << i;
18
Un test di uguaglianza corretto 2
Per decidere se due array di egual tipo e egual dimensione N hanno valori uguali per indici uguali, si devono confrontare tutti gli elementi usando un’iterazione. Ecco la traduzione della soluzione precedente in un ciclo FOR: i è dichiarata fuori del for perché l’if che segue ne possa fare uso int i; for (i=0; i < N && v[i] == w[i]; i++){ }; //il corpo del FOR e’ vuoto if (i == N) cout << "v,w hanno uguali per indici uguali"; else cout << "v, w hanno diverso l’elemento di posto" << i;
19
Passaggio di un vettore ad una funzione
Un array viene passato alle funzioni sempre per indirizzo. Attenzione: nella dichiarazione del parametro scriviamo int a[], nella chiamata non ripetiamo il tipo e scriviamo solo a: int sum( int a[], int n) /* prec.:0<=n<=dim.a post.cond:sum(a,n) = somma di a[0..n-1]*/ {int i,s; for (i=0,s=0; i<n; i++) s=s+a[i]; return s;} int main(){ int a[] = { 11, 33, 55, 77 }; int size = sizeof(a)/sizeof(int); //num.el. di a cout <<"sum(a,size) ="<<sum(a,size)<<endl;}
20
Modifica di un vettore Poiché un vettore viene passato per riferimento (indirizzo) se una chiamata di funzione modifica gli elementi del vettore, queste modifiche sono permanenti: void scambia (int v[], int i, int j) // pre: 0 i, j < dimensione di v // post: scambia v[i] con v[j] { int temp = v[i]; v[i] = v[j]; v[j] = temp; }
21
Inversione di un vettore v
Idea. Poniamo due indici i, j agli estremi di v e muoviamo i, j uno verso l’altro. Scambiamo tra loro gli elementi di posto i e j, fino a che tutti gli elementi alla sinistra di v sono scambiati con tutti gli elementi alla destra di v. void inverti (int v[], int n) /* PRE: 0 n dimensione di v. POST: elementi v[0..n-1] in ordine inverso */ {for (int i = 0, int j=n-1; i<j; i++,j--) scambia(v, i, j);} Attenzione: se un vettore v è un parametro attuale di una funzione (per es. scambia) NON si scrive int v[] ma v i=0 i=1 j=n-2 j=n-1 v[0] v[1] … v[n-2] v[n-1]
22
3. Ricerca Lineare e Binaria
Si vuole decidere se un intero n appartiene alla sequenza rappresentata dal vettore v. Il metodo più semplice è la ricerca lineare: confrontiamo n con v[0], v[1], v[2], … in quest’ordine. bool Member (int n, int v[], int dim) /* pre: la dimensione di v e’ >= dim >=0. post: restituiamo true esiste i tale che v[i]==n */ {bool trovato = false; /* “trovato” indica se n e’ gia’ stato trovato. “trovato” puo’ cambiare solo da false a true, mai viceversa.*/ for(int i=0;i<dim;i++){if(v[i]==n)trovato=true;} return trovato;}
23
Ricerca lineare con interruzione: uso di una variabile “flag”
Per efficienza, potremmo voler interrompere la ricerca di n non appena troviamo n. A tal fine, definiamo un valore booleano “trovato” che parte da “vero”, e non appena “trovato” vale vero usciamo. Il test del ciclo quindi deve essere: continuiamo se “!trovato” è vero. Una variabile booleana che ci avvisa quando uscire da un ciclo è detta una “flag”. bool Member (int n, int v[], int dim) /* pre: la dim. di v e’ >= dim >=0. post: true sse esiste i t.c. v[i] == n*/ {bool trovato = false; //detta variabile “flag” for (int i=0; i<dim && !trovato == true; i++) if (v[i] == n) trovato = true; return trovato;}
24
Ricerca lineare con interruzione: seconda soluzione
Possiamo eliminare la “flag” trovato, spostando (la negazione di) v[i] == n nel test del for. In tal caso, dobbiamo dichiarare i fuori dal for: bool Member (int n, int v[], int dim) // pre: la dimensione di v e’ >= dim >= 0 // post: true sse esiste i t.c. v[i] == n { int i; for (i=0; i < dim && v[i] != n; i++){}; return (i < dim);} Se i < dim è vero, il for è terminato perchè v[i] == n , altrimenti è terminato perchè il vettore è finito senza trovare n
25
Ricerca binaria Se un vettore (per es. di interi) è ordinato in senso crescente, la ricerca di un elemento nel vettore può essere enormemente accelerata sfruttando il metodo della Ricerca Binaria: Manteniamo due indici, i e j, a delimitazione della porzione v[i…j] di v in cui cercare Ad ogni passo confrontiamo n con il valore di indice medio in i..j, cioè m=(i+j)/2 Se v[m] != n allora cerchiamo in v[i..m-1] o in v[m+1..i] a seconda che n < v[m] oppure v[m] < n. Daremo ora una descrizione dettagliata del funzionamento della ricerca binaria, in 5 tappe.
26
Ricerca binaria 1: pre- e post-condizioni
1. Definiamo il problema. Input: il “valore cercato” in v è n. Pre-condizione: il vettore v di dimensione dim è ordinato. Post-condizione: restituire l’indice del valore cercato (un i tale che v[i]=n, se esiste), altrimenti la lunghezza dim di v (dim sta per “non trovato”) 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 dim-1=19 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 7 dim-1=19 Valore cercato: n = 25. Indice del valore cercato: 7 ( v[7]=25)
27
Ricerca binaria 2: una proprietà invariante
2. Individuiamo una proprietà “invariante” della ricerca binaria, cioè una proprietà significativa che resta vera durante tutta la durata della ricerca binaria: Propr. Invariante: durante la ricerca binaria considero solo dei segmenti v[i…j] di v tali che: se n è in v, allora n è in v[i…j]. v[i…j] 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 indice 0 i=3 indice 19 Cerco n=25 in v[i…j] j=16 Per es.: se n=25 è in v, allora n è in v[i..j] = v[3..16].
28
Ricerca binaria 3: il funzionamento
3. La ricerca binaria cerca un modo per avvicinarsi alla soluzione mantenendo vero l’invariante Passo generico: dividiamo il sottovettore in due parti (quasi) uguali. Caso 1. Se n si trova nel punto intermedio: restituisco m Spazio dove avviene la ricerca di n 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 dim-1= 19 Se il valore cercato è n = 43 allora l’ho trovato Punto intermedio m di i…j
29
Ricerca binaria 3: il funzionamento
3. La ricerca binaria cerca un modo per avvicinarsi alla soluzione mantenendo vero l’invariante Passo generico: dividiamo il sottovettore in due parti (quasi) uguali. Caso 2. Se il valore n cercato è < di quello nel punto intermedio, allora, dato che il vettore è ordinato, n si trova nella parte sinistra di v[i…j]. Spazio di ricerca 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 19 Punto intermedio m di i..j Valore cercato: n = 25
30
Ricerca binaria 3: il funzionamento
3. La ricerca binaria cerca un modo per avvicinarsi alla soluzione mantenendo vero l’invariante Passo generico: dividiamo il sottovettore in due parti (quasi) uguali. Caso 3. Se il valore cercato n è > di quello nel punto intermedio, allora n si trova nella parte destra di v[i…j] . Spazio di ricerca 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 19 Valore cercato: n = 60 Punto intermedio m di i..j
31
Ricerca binaria 4: la fine della computazione
4. Definiamo in quale momento la computazione si deve fermare Quando si sia trovato il valore nel punto intermedio di indice m, oppure …. Spazio di ricerca 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 19 Valore cercato (e trovato): n = 43 Punto intermedio di indice m
32
Ricerca binaria 4: la fine della computazione
4. Definiamo in quale momento la computazione si deve fermare …. oppure quando il sottovettore cui limitiamo la ricerca sia ridotto al vettore vuoto (cioe’ al vettore v[i…j] con i>j) 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 19 n=23 dovrebbe essere qui in mezzo, tra 21 e 25: ma questo intervallo è vuoto. Il valore n non viene trovato. Valore cercato (e non trovato): n=23
33
Ricerca binaria 5: l’inizio della computazione
5. Definiamo le condizioni iniziali per la ricerca binaria All’inizio, il segmento v[i…j] di vettore in cui cercare n e’ l’intero vettore n. Spazio di ricerca iniziale: v[0..n-1] 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 19
34
Ricerca binaria: i dettagli della codifica dei dati
Stabiliamo ora i dettagli della codifica del segmento di vettore V[i..j] che usiamo durante la ricerca. Il sottovettore V[i..j], a cui limitiamo la ricerca, è compreso tra le posizioni i e j incluse Spazio di ricerca in un passo generico della computazione 3 5 6 13 18 21 21 25 36 43 49 51 53 60 72 74 83 88 91 95 i m j 19 Il punto medio m ha indice: (i + j) diviso 2 Se i > j allora il sottovettore V[i..j] è vuoto
35
Ricerca binaria: l’implementazione
Scriviamo ora una funzione C++ che implementa la ricerca binaria, usando pre- e post-condizioni e l’invariante come commenti. La funzione ottenuta è decisamente breve rispetto a tutta la discussione che è servita a presentarla.
36
Ricerca binaria: l’implementazione
int binsearch (int n, int v[], int dim) // pre: la dim. di v e’ >= dim e v[0..dim-1] è ordinato // post: i tale che v[i] == n se ne esiste uno, altrimenti: dim { int i = 0, j = dim - 1, m; while (i <= j) //inv. se n in v[0..n-1] allora n in V[i..j] {m = (i+j)/2; if (v[m] == n) return m; else if (n < v[m]) j = m - 1; else /* (v[m] < n) */ i = m + 1;} return dim; // dim sta per “non trovato” }
37
4. Matrici in C++ Una matrice a due dimensioni viene vista come un vettore bidimensionale, o di vettori, ognuno dei quali rappresenta una riga della matrice; la dichiarazione di una matrice è simile a quella vettore, eccetto che richiede due dimensioni: double A[10][20]; // matrice 10righe x 20colonne di double A[i][j] = 7.23; // se 0 i < 10 e 0 j < 20 allora // scrive 7.23 come valore della // i-esima riga e j-esima colonna di A
38
Passaggio di un vettore bidimensionale a funzione
Nei parametri formali di una funzione un vettore V di dimensione 1 può figurare come void f(int V[], int n){…} senza l’indicazione della lunghezza di V dentro int V[]: la lunghezza n del vettore è a sua volta un parametro, che può cambiare da una chiamata all’altra. Nel caso di una matrice A di due o più dimensioni, invece, le dimensioni debbono essere costanti indicate dentro A stesso, come segue: void g(double A [10][20] ) {…}
39
Passaggio di un vettore bidimensionale a funzione
Questo tipo di dichiarazione è molto scomoda: una funzione g che stampa una matrice A di 10x20 elementi non può essere utilizzata per stampare una matrice B di 20x20 elementi, perchè double A[10][20] e double B[20][20] sono due tipi diversi. La seconda dimensione di A, ovvero il numero 20 delle colonne di A, è purtroppo necessaria per ricostruire l’indirizzo della variabile A[i][j] nella macchina di Von Neumann, e non è ricostruibile a partire dalla sola variabile A. void g(double A [10][20] ) {…}
40
Un esempio di uso di matrici: il triangolo di Tartaglia
Scriveremo ora una funzione che assegna le prime n+1 righe del triangolo diTartaglia a una matrice (n+1)x(n+1). Per definizione, ogni elemento posto ai lati del triangolo di Tartaglia vale 1, e ogni altro elemento è la somma dell’elemento posto sopra e di quello posto sopra e a destra. Niccolò Tartaglia
41
Un esempio di uso di matrici: il triangolo di Tartaglia
Righe da 0 a 6 del “Triangolo” in una matrice A di 7x7. Per definizione: 1 = A[0][0] = A[1,0] = A[2][0] = … =A[i,0] = … e 1 = A[0][0] = A[1,1] = A[2][2] = … = A[i,i] = … e per 0<j<i: A[i][j] = A[i- 1][j-1]+A[i-1][j]. 1 1 2 3 4 5 6 Per es.: 6 = A[4][2] = A[3][1] + A[3][2] =
42
Il triangolo di Tartaglia usando una matrice
void Tartaglia(int n) // stampa righe da 0 a n del triangolo di Tartaglia {int a[n+1][n+1]; //definisce matrice (n+1)x(n+1) for (int i = 0; i<=n; ++i) // costruzione “riga per riga” {a[i][0] = 1; // assegna 1 a tutta la colonna 0 for (int j = 1; j<i; ++j) // assegna colonne da 1 a i-1 a[i][j] = a[i-1][j-1] + a[i-1][j]; a[i][i] = 1; // assegna 1 a tutta la diagonale} // stampa righe da 0 a n del triangolo …(vedi pagina seguente per sapere come) … }
43
Stampa del triangolo di Tartaglia
void Tartaglia(int n) { // definisce righe da 0 a n … (vedi pagina precedente per sapere come) … // stampa righe da 0 a n for (int i = 0; i <= n; ++i) { for (int j = 0; j <= i; ++j) cout << setw(4) << a[i][j]; cout << endl;} } L’istruzione setw(4) esegue la prossima stampa con almeno 4 spazi. Richiede di includere la libreria: #include <iomanip.h>
44
5. I records (cenni) Un record è una tupla di valori di tipo possibilmente diverso (è questa la differenza con i vettori) a cui accediamo attraverso etichette anziché indici: struct <nome struttura> { <tipo1> <etichetta campo1>; ... <tipok> <etichetta campok>;} Come concetto matematico, un record corrisponde a un prodotto cartesiano: tipo1 x … x tipon mentre un vettore corrisponde a un insieme potenza: tipon
45
I record nella memoria I record nella memoria di una macchina di Von Neumann sono rappresentati con celle adiacenti, ma di diversa dimensione. E’ necessario individuare ogni cella assegnadole un nome: Nome_1 … Nome_k Possiamo rappresentare i razionali come frazioni, e le frazioni come un record di due campi: numeratore e denominatore. Si tratta solo di un esempio: i razionali non sono una struttura dati abbastanza complessa da giustificare l’uso dei records.
46
Frazioni rappresentate da un record
Poiché qui i due campi hanno lo stesso tipo avremmo potuto scrivere: int num, den; Ratio si aggiunge ai tipi definiti nel programma struct Ratio { int num; int den;}; Se r e’ un record che rappresenta una frazione, indichiamo numeratore e denominatore di r con r.num e r.den
47
Record come valori di funzioni
Diversamente dagli array, le struct in C++ sono passate (e restituite) per valore: dunque ogni chiamata costruisce una copia del record e la assegna al parametro formale della funzione Ratio NewRatio(int n, int d) /* Pre-cond.: d!=0 Post-cond.:NewRatio(n,d) restituisce il record che rappresenta n/d */ { Ratio r; r.num = n; r.den = d; return r;} int main() { Ratio a = NewRatio(2,3); // a=2/3 }
48
Record come valori di funzioni
Un altro esempio, la somma di frazioni. Le strutture in C++ sono passate per valore, creando delle copie dei valori passati. Ratio SumRatio(Ratio a, Ratio b) // post: restituisce il razionale a + b { Ratio r; r.num = a.num * b.den + a.den * a.num; r.den = a.den * b.den; return r;} int main() { Ratio a, b; …; Ratio c = SumRatio(a,b);} // c = a + b
49
Vettori parzialmente riempiti
Di un vettore occorre ricordare la dimensione; se poi se ne usa solo una parte, come abbiamo fatto nell’esercizio sui numeri primi, bisogna sapere sin dove è “riempito”, ovvero, quale è il prossimo indirizzo libero. v prox_libero Se non ci sono indirizzi liberi, il prossimo indirizzo libero per definizione è la dimensione dim del vettore v.
50
Vettori parzialmente riempiti come record
Possiamo definire un record per rappresentare vettori parzialmente riempiti. Usiamo un record con due campi: un vettore e il primo indirizzo ancora libero del vettore (se esiste) struct Array { int v[10]; int prox_libero; }; /* prox_libero = indice del prossimo indirizzo libero */
51
Funzioni su vettori parzialmente riempiti
Un esempio di una funzione che agisce sui vettori parzialmente riempiti: la stampa di tutti gli elementi del vettore effettivamente in uso (dunque fino alla prossima posizione libera esclusa). void Mostra(Array a) /*post: stampa la parte riempita di v, e cioé: (a.v)[0..a.prox_libera-1] */ { for (int i = 0; i < a.prox_libero; i++) cout << a.v[i] << " "; cout << endl;}
52
Funzioni su vettori parzialmente riempiti
Un altro esempio di una funzione che agisce sui vettori parzialmente riempiti: come aggiungere un elemento a quelli effettivamente in uso bool Aggiungi(int n, Array& a) /* post: se a.prox_libera < 10, aggiunge n in ultima pos. e restituisce true; restituisce false altrimenti */ {if (a.prox_libero < 10) {a.v[a.prox_libero] = n; a.prox_libero++; return true;} else return false;}
53
Riepilogo Vi sono due strutture dati predefinite per rappresentare collezioni finite di valori: vettori (array) e record (struct) I vettori hanno dimensione fissa, elementi omogenei, e sono passati per riferimento Vettori a due dimensioni rappresentano una matrice. I record hanno un numero fisso di campi individuati da nomi, hanno tipi eventualmente diversi di valori, e sono passati per valore.
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.