Realizzazione software • Due fasi: 1. Specifica dell'algoritmo 1.a 1.b Definizione dei dati Definizione della modalità della loro elaborazione 2. Realizzazione algoritmo con un particolare linguaggio (traduzione) Tipi di dati • Tipo di dato astratto: oggetto matematico definito da tre componenti: – insieme di valori che definisce il dominio – insieme di operazioni sul dominio – insieme di costanti • Esempio: tipo booleano: • {true, false} • and, or, not, ... • true, false Tipi di dati • Tipo di dato concreto: si riferisce all'uso del dato in un particolare linguaggio • Per definire un tipo di dato concreto occorre: – definire le proprietà astratte – definire i vincoli imposti dal linguaggio scelto • ad esempio: come dichiararlo, utilizzarlo, accedere alle sue parti,... Rappresentazione di un nuovo tipo di dato • Per rappresentare un nuovo tipo di dato, può essere necessario utilizzare tipi di dati già esistenti • Esempio: tipo di dato: "insieme [1..5]" • Realizzato con un vettore di 5 elementi • I metodi sono composizioni dei metodi utilizzati dai dati componenti Rappresentazione di un nuovo tipo di dato • Esempio: – inserimento di un elemento nell'insieme – rimozione di un elemento dall'insieme – svuotamento dell'insieme – controllo della presenza di un elemento – controllo dello stato dell'insieme (pieno, vuoto, stati intermedi) Rappresentazione dei dati • La rappresentazione di un nuovo dato non è univoca • I criteri di scelta sono: – la correttezza e – l'efficienza della rappresentazione, misurata da: • occupazione in memoria • costo di esecuzione delle operazioni Diverse rappresentazioni • Esempio: insieme di interi [1..5] – con un vettore di 5 elementi booleani – con un unico intero di 5 bit • Differenza di efficienza: – Inserimento di un el.: – Controllo dello stato di un el.: – Azzeramento: – Unione: Vettori e matrici • Si mettono in corrispondenza un insieme di indici e gli elementi del vettore – Gli indici sono definiti interi – I metodi sono generalmente: memorizza e accedi • Una matrice è definita come un vettore a due dimensioni Rappresentazione di vettori • In locazioni di memoria contigue • Si definisce l'indirizzo della prima locazione e la dimensione di ogni elemento • Accesso all'elemento i-esimo: ind(el i) = ind(el 0) + i*size(el) Vettori a più dimensioni • Esempio a due dimensioni: – Row major order • Accesso all'elemento (i,j)-esimo: ind( el i,j ) = ind(el 0,0) + (j+i*N)*size(el) • Facile estensione a più di due dimensioni Rappresentazione compatta di vettori • Matrici sparse con valore predominante – per velocizzare l'elaborazione – per risparmiare memoria • Esempio con vettore a tre componenti – memorizzazione dimensione matrice e valore predominante Rappresentazione compatta di vettori • Metodi di accesso agli elementi: – accedi (complesso) – memorizza (molto complesso, richiede shift) • Funzioni composte: – controllo dello stato – controllo del numero degli elementi • Risparmio di memoria Le liste semplici • I valori di una lista sono sequenze di valori elementari, detti atomi • Esempio di lista di interi mediante rappresentazione parentetica: ( 8 25 6 87 54 ) • Caratteristiche: – lunghezza non definita a priori – presenza della lista nulla ( ) Metodi sulle liste • • • • • Lunghezza (numero di elementi) cons(el, lista) per inserire un elemento in testa alla lista car(lista) determina il primo elemento cdr(lista) fornisce una copia della lista senza il primo elemento null(lista) verifica se la lista è vuota Rappr. delle liste semplici • Pochi linguaggi dispongono del tipo concreto lista • Vi sono due tipi di rappresentazione: – rappr. sequenziale – rappr. collegata Rappresentazione sequenziale • E' rappresentata da: – un vettore monodimensionale i cui elementi contengono un atomo – un intero (primo) che denota l'indice del vettore che identifica il primo elemento – un intero (lunghezza) che denota il numero di elementi nella lista Rappresentazione sequenziale (5 1 21 45 78) 5 1 21 45 78 12 1 7 1 2 3 4 5 6 7 8 primo = 1 lunghezza = 5 Rappresentazione sequenziale • Implementazione dei metodi • Svantaggi: – occupazione fissa di memoria – limiti nell'estensione della lista – inefficienza di alcuni metodi Rappresentazione collegata • Ad ogni elemento è associato un riferimento che serve a determinare il successore • La sequenza non è più rappresentata dall'adiacenza fisica in memoria, ma da una informazione logica Rappresentazione collegata • Implementazione dei metodi: – eliminazione primo elemento – aggiunta di un elemento in testa – eliminazione di un elemento generico – aggiunta di un elemento in una posizione generica Rappresentazione collegata • Vantaggio: – non più necessario spostare elementi (solo modifiche ai riferimenti) • Svantaggio: – per accedere ad un elemento è necessario scandire tutta la lista (cioè non è noto l'indirizzo del generico elemento) Implementazione della rappresentazione collegata • Vi sono due modi per implementare la rappresentazione collegata: – utilizzando gli array – utilizzando i puntatori Rappresentazione collegata mediante array • Si associa ad ogni elemento della lista una componente dell'array costituita da: – il valore dell'elemento della lista – il riferimento all'elemento successivo (indice dell'array) Rappresentazione collegata mediante array (5 1 21 45 78) 21 4 5 6 ? ? 45 7 ? ? 1 1 78 0 ? ? 1 2 3 4 5 6 7 8 inizio = 2 Rappresentazione collegata mediante array • Metodi: – l'azzeramento e l'eliminazione di elementi sono operazioni semplici – l'inserimento di elementi necessita della determinazione di una posizione vuota che si può realizzare in due modi: • scansione dell'intera lista • utilizzo della lista libera (esempi) Rappresentazione collegata mediante array • Vantaggi: – non vengono spostati elementi – linguaggi in cui l'unico dato struttturato è l'array • Svantaggi: – gestione della lista libera – rimane il problema della dimensione massima fissata dalla dimensione dell'array – richiede più memoria a causa dei riferimenti Rappresentazione collegata mediante puntatore • Il tipo puntatore è un tipo di dato i cui valori rappresentano indirizzi in memoria • Le operazioni usualmente disponibili sono: – accesso alla locazione puntata – richiesta di una nuova locazione libera – rilascio della locazione non più utilizzata Rappresentazione collegata mediante puntatore • Ogni elemento della lista è composto da: – il valore dell'elemento della lista – un puntatore che identifica la locazione di memoria in cui è memorizzato l'elemento successivo • L'elemento iniziale è un puntatore Rappresentazione collegata mediante puntatore • Vantaggi: – stessi vantaggi della rappresentazione collegata mediante array e in più non c'è limite alla lunghezza massima • Svantaggi: – la ricerca richiede la scansione completa L'utilizzo dei puntatori è critico • L'utilizzo dei puntatori permette di referenziare zone di memoria; è critico perché: – permette di modificare aree di memoria che possono contenere informazioni vitali – se mal utilizzato, può portare all'esaurimento della memoria disponibile (garbage collection) Rappresentazione collegata • Per migliorare l'efficienza di alcune operazioni sono state concepite due varianti: – Rappresentazione collegata circolare – Rappresentazione collegata simmetrica Rappresentazione collegata circolare • L'ultimo elemento non contiene un riferimento nullo, ma il riferimento al primo elemento della lista • Vantaggi: – utilizzo come buffer circolare Rappresentazione collegata simmetrica • Ogni elemento contiene anche il riferimento all'elemento precedente • Vantaggi: – la lista si può scandire in entrambe le direzioni – si semplifica l'inserimento in posizione precedente ad un dato elemento Liste composite • Estensione del concetto di lista • Gli elementi della lista possono a loro volta essere delle liste • Rappresentazione parentetica: ( 5 () 6 ( 7 8 ) ( 9 (12) 3 ) 14 ) • Nell'esempio, l'atomo può essere una lista o un numero Rappresentazione del singolo nodo • Esistono due varianti: – l'atomo contiene sia un puntatore ad una lista che lo spazio per memorizzare un numero; un ulteriore booleano li seleziona – l'atomo contiene lo spazio per memorizzare solo il più esteso tra il puntatore alla lista e il numero; un ulteriore booleano li seleziona Rappresentazione del singolo nodo • Le due varianti si riferiscono a: strutture (struct) typedef struct { int giorno; int mese; int anno; } data; unioni (union) typedef union { int numero; char nome[10]; } cliente; Recupero della memoria • Garbage collection (recupero memoria non più utilizzata) • Può avvenire: – manualmente a carico del programmatore – automaticamente a carico del traduttore del linguaggio (serve marcare le aree allocate e gestire la lista libera) Le pile • La pila è un tipo di dato con struttura LIFO • Definizione: – {pila, elemento, boolean} – {top, push, pop, test_pila_vuota} • top: pila elemento • push: pila x elemento pila • pop: pila pila • test_pila_vuota: pila boolean (cons) (cdr) (car) (null) – {pila_vuota} Le pile • A differenza delle liste gli inserimenti e le cancellazioni posso essere effettuati solo sulla cima della pila (non avvengono spostamenti degli elementi) • Tipo di dato fondamentale Le code • La coda è un tipo di dato con struttura FIFO • Definizione: – {coda, elemento, boolean} – {primo, in_coda, out_coda, test_coda_vuota} • primo: coda elemento • in_coda: coda x elemento coda • out_coda: coda coda • test_coda_vuota: coda boolean (cons) (cdr) (car) (null) – {coda_vuota} Requisiti delle pile e delle code • Requisiti delle pile: – un puntatore che determini la cima – le operazioni di accesso sono semplici • Requisiti delle code: – due puntatori che puntino alla cima e alla coda – le operazioni di accesso sono poco più complesse