Tipi di Dati Astratti - eziobartocci.com · Laboratorio di Algoritmi e Strutture Dati - AA...
Transcript of Tipi di Dati Astratti - eziobartocci.com · Laboratorio di Algoritmi e Strutture Dati - AA...
Tipi di Dati Astratti
Dott. Francesco De Angelis, Dott. Ezio Bartocci
Laboratorio di Algoritmi e Strutture Dati - AA 2006/2007
Dip. di Matematica e InformaticaUniversità di Camerino
12 dicembre 2006
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Modelli astratti
Lo sviluppo di Modelli Astratti dei dati, e dei modi in cui iprogrammi elaborano dati, costituisce la base per la risoluzionedei problemi attraverso l’uso di un calcolatore
Introduciamo l’uso degli ADT (Abstract Data Type) che ciforniscono astrazioni di alto livello per la scrittura dei programmi
Con gli ADT possiamo mantenere distinte le trasformazioniconcettuali dei software dalla specifica strutturazione dei dati edalle implementazioni algoritmiche delle operazioni su di essi
2 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Modelli astratti
L’uso di ADT ci svincola dai dettagli implementativi
Identificare le operazioni rilevanti nei programmi e lecaratteristiche dei dati per poterle definire in termini astratti
Sviluppo di meccanismi concreti che supportino operazioni e dati
Per usare gli ADT è necessario:
definire gli oggetti astratti e le operazioni che vogliamo eseguiresu essi
rappresentare i dati con una struttura dati e implementare leoperazioni su esse
3 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Abstract Data Type
DefinitionUn ADT è un tipo di dato (cioè un insieme di valori e una collezione dioperazioni su questi valori) accessibile solo attraverso un’interfaccia
Chiameremo programma client un programma che usa un ADT, eimplementazione un programma che specifica il tipo di dato
Particolare attenzione va fatta per la parola ”solo”, cioè significache con un ADT un programma client ha accesso ai datiutilizzando esclusivamente le operazioni fornite dall’interfacciadell’ADT.
L’implementazione è tenuta completamente separata dalprogramma client attraverso l’interfaccia
4 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di ADT: classe Point
Implementazione di Point
class Point{
private double x, y;Point(){
x = Math.random();y = Math.random();
}Point(double x, double y){
this.x = x;this.y = y;
}double x(){
return x;}double y(){
return y;}double r(){
return Math.sqrt(x*x + y*y);}public String toString(){
return "(" + x + ", " + y + ")";}
}
Implementazione di un ADT
L’accesso alle informazioni èregolato dalla keywordprivate
Un membro privato puòessere acceduto soloall’interno della classe
I client possono accedere emanipolare i dati soloutilizzando i metodi pubblici
5 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Attributi di Accesso in Java
private Visibilità solo all’interno della classe
protected Visibilità a livello di package
public Visibilità esterna alla classe e al package
Informalmente utilizzeremo il termine pubblico per i metodi accessibilidai client e privato per i metodi utilizzati dalla classe stessa.
6 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Metodi di Accesso
I metodi dell’esempio precedente x() e y() sono detti metodi diaccesso
Oggetti che non possiedono metodi per la modifica dei dati unavolta che sono stati creati sono detti immutabili
AttenzioneSe non permettiamo ai client di accedere direttamente allarappresentazione dei dati, ma usiamo metodi di accesso, siamo liberidi cambiare la rappresentazione!
Possibilità di miglioramenti dell’implementazione
Correzione di errori senza modifiche ai client
Test di diverse implementazioni per valutare affidabilità,prestazioni...
7 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di interfaccia
Interfaccia di Point
Class Point{ // implementations
// and private members hiddenPoint()Point(double, double)double x()double y()double r()double theta()double distance(Point)public String toString()
}
Come si lega il concetto di classeJava con lo schema client-interfaccia-implementazione?
Adottiamo la seguenteconvenzione circa le interfacce:
le segnature dei metodi chenon sono privatecostituiscono l’interfacciadella classe
i membri di una classe chenon fanno partedell’interfaccia sono privati
8 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Interfaccia e Contratto
Un’interfaccia stabilisce il “contratto” che viene a crearsi traprogrammi client e implementazioni
E’ possibile utilizzare lo strumento java interface.
Attenzioneinterface non supporta i costruttori dell’oggetto, quindi in unainterfaccia Java non abbiamo i costruttori ma nell’implemantazione si.Questo viola quanto detto finora perchè i client accedono ai costruttorisenza passare per l’interfaccia.
Le implementazioni sono spesso chiamate Tipi di dati concreti
9 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Quindi...
Gli ADT sono un meccanismo efficace per supportare laprogrammazione modulare come principio di organizzazione deimoderni sistemi software
GLi ADT forniscono la flessibilità necessaria per rendere agevolimodifiche e miglioramenti di fondamentali strutture dati ealgoritmi di base del sistema che si sta sviluppando
Progettare un ADT è solo il primo passo! dovremo anche fornireefficaci implementazioni delle operazioni associate e dellestrutture dati sottostanti
Con gli ADT possiamo usare modelli astratti per testare algoritmie strutture dati: realizziamo il client che usa un ADT poiconfrontiamo più implementazioni
10 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Collezioni di oggetti
Molti ADT definiscono operazioni su collezioni di oggettiTipicamente avremo due tipi di operazioni basilari su unacollezione di dati:
insert che inserisce un nuovo elementodelete che cancella un elemento dalla collezione
Chiamiamo questi ADT Code generalizzate
Mentre insert è un’operazione dal chiaro significato, per deletepossiamo usare criteri differenti per decidere quale elementorimuovere (avremo ADT differenti a seconda della scelta)
Per ogni ADT dovremo effettuare delle scelte per le strutture datie per l’implementazione delle operazioni (tenendo conto dellaloro complessità)
11 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
ADT Stack
DefinitionUno stack è un ADT che supporta due operazioni di base: inserimento(push, inserisci in cima) di un nuovo elemento e cancellazione (pop,preleva dalla cima) dell’elemento che è stato inserito più di recente
Lo stack (o “pila”) è il più importante fra i tipi di dati chesupportano le operazioni insert e delete
Ci riferiamo ad una descrizione delle operazioni push e pop chesia sufficientemente dettagliata da poter essere usata dai client
Necessaria una implementazione che rispetti la regola checaratterizza uno stack gli elementi sono rimossi secondo unapolitica LIFO (Last In, First Out, “l’ultimo a entrare è il primo auscire”)
12 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Esempio di stack
La prima colonna mostra l’operazione effettuata sullo stack (unalettera indica una push mentre un “*” indica una pop, nella secondacolonna viene mostrata la lettera estratta, nella terza colonna lo statodello stack. L’elemento più recente è sulla destra.
Example
L LA L A* A LS L ST L S TI L S T I* I L S T
13 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Esempio di stack
Nell’implementazione siamo liberi di organizzare gli elementi nel modoche desideriamo purchè diamo “l’illusione” ai programmi client che glielementi siano organizzati in questo modo
Interfaccia Stack
class intStack // ADT interface{ // implementations
// and private members hiddenintStack(int)int empty()void push(int)int pop()
}
AttenzioneQuesto stack lavora con elementi che sono numeri interi. int in Java.
14 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Esempio di valutazione di espressione postfissa
InformazioneOgni espressione aritmetica con *, /, +, -, (, ), può essere espressa:
5 * ( ( ( 9 + 8 ) * ( 4 * 6 ) ) + 7 ) Forma Infissa5 9 8 + 4 6 * * 7 + * Forma Postfissa
Per la valutazione: push per ogni operando, pop di due operandi per ognioperatore, calcolo operazione e push del risultato
Example
5 59 5 98 5 9 8+ 5 17
4 5 17 46 5 17 4 6* 5 17 24* 5 408
7 5 408 7+ 5 415* 2075
15 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Esempio di utilizzo
Possiamo definire allo stesso modo un procedimento che facciauso di stack per tradurre l’espressione infissa in postfissa.In questo modo avremmo:
l’input (espressione infissa) convertito in una rappresentazioneintermedia (espressione postfissa)algoritmo che basandosi sullo stack valuta l’operazione
AttenzionePer la valutazione abbiamo usato uno stack di interi. Per laconversione infisso-postfisso potremmo utilizzare uno stack di caratteri(si tratta di riscrivere l’espressione!). Per ora abbiamo strutture chegestiscono collezioni di oggetti con un tipo definito int o char
16 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Implementazione dell’ADT stack
Consideriamo ora due implementazioni:1 basata su array2 basata su liste concatenate
Se usiamo un array abbiamo la necessità di tener traccia della cimadello stack
una push() corrisponde alla memorizzazione dell’elemento nellaposizione puntata dall’indice e ad un incremento dell’indice
una pop() corrisponde ad un decremento dell’indice e allarestituzione l’elemento puntato
17 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Stack di interi con array
Stack di int con array
class intStack{
private int[] s;private int N;intStack(int maxN)
{ s = new int[maxN]; N = 0; }boolean isEmpty()
{ return (N == 0); }void push(int item)
{ s[N++] = item; }int pop()
{ return s[--N]; }}
Oltre alla push e alla pop è stata implementata la funzioneisEmpty
Nel costruttore si alloca un array di dimensioni predefinite
18 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Stack di caratteri con array
L’implementazione vista precedentemente gestisce elementi di tipoint. Se volessimo gestire char dovremmo cambiare il tiponell’implementazione.
AttenzioneQuesto approccio ha il vantaggio di fornire implementazioni che sianospecifiche per il tipo di dato considerato, ma ha lo svantaggio diportare alla proliferazione di classi che hanno lo stesso codice!
19 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Uso di liste concatenate
Lo svantaggio dell’uso di un array è quello di dover allocare unastruttura dati di dimensione predefinita.Usando una lista concatenata otteniamo invece, uno stack checresce con le push e si contrae con le pop.
Utilizzando una lista concatenata:per eseguire una pop rimuoviamo il nodo dalla testa della lista ene restituiamo il contenutoper eseguire una push creiamo un nuovo nodo e lo aggungiamoalla testa della lista
AttenzioneTutte le operazioni i svolgono in testa.
La rappresentazione interna degli elementi è diversa rispetto alcaso precedente, ma ciò non è “percepibile” dal client esterno.
20 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Stack di interi con lista concatenata
Stack di int con listaconcatenata
class intStack{
private int[] s;private int N;intStack(int maxN)
{ s = new int[maxN]; N = 0; }boolean isEmpty()
{ return (N == 0); }void push(int item)
{ s[N++] = item; }int pop()
{ return s[--N]; }}
21 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Confronto
L’implementazione con array occupa uno spazio necessario amemorizzare il massimo numero di elementi attesi durante ilcalcoloL’implementazione con la lista richiede più tempo nelle operazionidi push e pop per allocare e deallocare la memoria ma necessitadi uno spazio proporzionale al numero (indefinito) di elementi
AttenzioneCi troviamo spesso nelle condizioni di dover scegliere tra diversecaratteristiche implementative
Proprietà
Le operazioni di push e pop dell’ADT stack usano tempo costante sianell’implementazione con array che in quella con liste concatenate
22 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Implementazioni generiche
Possiamo rendere le definizionidegli stack generiche in modo danon dover ripetere porzioni dicodice. In Java possiamo sfruttarel’ereditarietà e implementare stackche gestiscano il tipo Objectquindi assegnare all’elemento iltipo corretto con un cast quando losi estrae dallo stack.
Stack generico
class Stack{
private Object[] s;private int N;Stack(int maxN)
{ s = new Object[maxN]; N = 0; }boolean isEmpty()
{ return (N == 0); }void push(Object item)
{ s[N++] = item; }Object pop()
{ Object t = s[--N]; s[N] = null;return t; }
}
23 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Implementazioni generiche
Per usare l’implementazione generica precedente con tipiprimitivi int e char dobbiamo uare le classi wrapper Integere Character (aggiungendo un livello di indirezione ulteriore)
Nulla vieta di inserire nello stack tipi di dati diversi tra loro,generando problemi in fase di esecuzione.
AttenzionePossiamo creare stack per tipi definiti usando lo stack generico. Sitratta di creare classi adattatrici che nascondano l’implementazionegenerica. In questo modo riusiamo il codice “generico”.
24 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Creazione di nuovi ADT
Per sviluppare un nuovo ADT occorre:
individuare le operazioni fondamentali sui dati dell’applicazioneanalizzata
definiamo un’interfaccia e scriviamo il codice di un ipotetico clientper verificare l’efficaia dell’atrazione fatta cercando di migliorarla
definiamo un’implementazione il più possibile effifiente dell’ADT
Implementazione dell’ADT e del client a un certo puntoprocedono indipendentemente
25 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Creazione di nuovi ADT
Questa separazione porta a:
separare il problema astratto (affrontato nel client) da problemipiù concreti (affrontati nell’ADT)
fornisce un metodo per confrontare algoritmi e strutture datidifferenti
fornisce un metodo per sviluppare altri algoritmi (riusando ADTesistenti)
fornisce un meccanismo per aggiornare la rappresentazionesenza modificare i programmi
26 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazione con arrayImplementazione con lista concatenataConsiderazioni
Meccanismi offerti da Java
Il meccanismo offerto da Java per separare l’interfacciadall’implementazione è basato sull’ereditarietà.
I metodi dichiarati abstract devono essere necessariamenteridefiniti dalle classi derivate, non ne viene data implementazione
Una classe con metodi astratti di dice classe astratta
27 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Code FIFO e code generalizzate
La coda FIFO (First-In, First-Out) è un altro fondamentale ADT. E’simile ad uno stack ma usa la regola opposta per lacancellazione. Viene rimosso quello che è rimasto nella coda piùa lungo.
DefinitionUna coda FIFO è un ADT che include due operazioni di base: put(inserisci un nuovo elemento) e get (preleva e cancella l’elemento cheè stato inserito meno recentemente).
28 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Code FIFO e code generalizzate
Interfaccia per l’ADT coda
class intQueue // ADT interface{ // implementations
// and private members hiddenintQueue(int)int empty()void put(int)int get()
}
Quest’interfaccia differisce daquella per lo stack solo per laterminologia!
Il comportamento è peròdiverso, ciò sottolinea lacomponente essenziale di unADT: l’astrazione.
29 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Code FIFO e code generalizzate
Example
F FI F IR F I RS F I R S* F I R ST I R S T* I R S T
Ogni get riduce la dimensionedella coda e ogni put l’aumenta.Nella figura gli elementi sonoorganizzati nell’ordine in cui sonoinseriti, ma in unaimplementazione reale siamo liberidi organizzare la rappresentazioneinterna degli elementi comevogliamo. Dall’esterno si devecomunque avere l’illusione che glielementi siano regolati da unadisciplina FIFO.
30 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Uso di liste concatenate
Rispetto alla stack gli elementisono ordinati in modo inverso.Utilizziamo due puntatori:
uno all’inizio: head (inmodo da poter estrarre ilprimo elemento)uno alla fine: tail (in mododa poter accodare unnuovo elemento)
31 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Coda di interi con lista concatenata
Implementazione di FIFO con lista concatenata
class intQueue{
private class Node{ int item; Node next;
Node(int item){ this.item = item;
next = null; }}
private Node head, tail;intQueue(int max)
{ head = null; tail = null; }boolean empty()
{ return (head == null); }void put(int item)
{ Node t = tail;tail = new Node(item);if (empty()) head = tail;else t.next = tail; }
int get(){ int v = head.item;
Node t = head.next;head = t;return v; }
}
32 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Coda di interi con array
Implementazione di FIFO tramitearray
class intQueue{
private int[] q;private int N, head, tail;intQueue(int maxN)
{ q = new int[maxN + 1];N = maxN + 1; head = N; tail = 0; }
boolean empty(){ return (head % N == tail); }
void put(int item){ q[tail++] = item;
tail = tail % N; }int get()
{ head = head % N;return q[head++]; }
}
Due indici, uno alla testa euno alla fine, consideriamo glielementi compresi tra i due
Una sequenza di put e get famuovere la coda nell’array,alla fine la coda si “riavvolge”su se stessa
Proprietà
Possiamo implementare leoperazioni get e put per l’ADTcoda FIFO in tempo costante siausando array che usando listeconcatenate.
33 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Considerazioni
Useremo spesso gli stack durante il corso, ciò è dovuto allarelazione fondamentale tra stack e programmazione ricorsiva
La correttezza di molte applicazioni non dipende dal tipo di regolaadottata per la cancellazione ma l’uso di risorse e le prestazionipotrebbero risentirnePer valutare l’efficacia dobbiamo considerare:
il costo di implementazione, dipendente dalle scelte fatte peralgoritmi e strutture datila misura in cui le scelte fatte influenzano i programmi client
AttenzioneStack e code FIFO sono un caso particolare di un ADT più generale:la coda generalizzata. Le code differiscono tra loro per la politica dicancellazione/rimozione degli elementi.
34 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Considerazioni
Possiamo stabilire una politica di cancellazione casuale perottenere una coda casuale
Oppure, invece che basarsi sull’ordine di inserimento potremmobasarci su di un ordinamento sequenziale
35 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Elementi duplicati
Per molte applicazioni gli elementi astratti sono uniciDobbiamo apportare modifiche alle implementazioni in modo chevietino la presenza di elementi duplicati
Possiamo modificare i client lasciando a loro il compito di gestire iduplicatiPossiamo modificare l’astrazione fornita da un ADT per delegargliquesto compito, l’interfaccia rimane la stessa ma varia in manierasostanziale l’implementazione
36 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Elementi duplicati
Il punto sostanziale è come gestire i duplicati, due politiche
ignorare il nuovo elemento (non richiede modifiche alla strutturadati)
dimenticare il vecchio elemento (richiede di rimuovere il vecchioelemento e reinserirlo nuovamente)
Abbiamo comunque bisogno di un metodo per verificare l’uguaglianzatra elementi.
AttenzioneJava mette a disposizione il metodo equals definito per tutti glioggetti, ma questo metodi va reimplementato poichè considera unoggetto uguale solo a se stesso!
37 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Elementi duplicati
“ignora il nuovo elemento”
Example
F I N FI I N F _* I N FR N F RS N F R S* N F R S* F R S
“dimentica il vecchio elemento”
Example
F I N FI N F I _* N F IR F I RS F I R S* F I R S* I R S
38 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Esempio con stack di interi
Analizziamo un caso particolare: uno stack di interi compresi tra 0 eM−1
Utilizziamo un secondo array (P) indicizzato dagli elementi perdeterminare se l’elemento i è presente P[i] = true o menoP[i] = false
Ulteriore test su P[i] quando inseriamo l’elemento i , seP[i] == true ignoriamo la push (nel caso “ignora il nuovo”)
Il caso “dimentica il vecchio elemento” richiede chiaramente dellavoro in più
39 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Definizione ed esempiImplementazioniConsiderazioniGestione di elementi duplicati
Elementi duplicati
Ciascuna scelta di vietare o meno duplicati, o usare o meno ilnuovo elemento porta ad ADT diversi
Parliamo di diversi ADT perchè essi sono visti dai client con uncomportamento diverso (pur avendo la stessa interfaccia!) eperchè utilizzano strutture dati e algoritmi diversi tra loro
Ci riferiamo a stack, code FIFO, code doppie (deque), code conpriorità, come a una famiglia di ADT. Ciascun ADT ha le sueimplementazioni e diverse convenzioni circa il significto dellevarie operazioni
40 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Rappresentazione di numeri complessi
Java considera in maniera diversa tipi primitivi (int, char, etc.)e oggetti
Non possiamo definire ad esempio le usuali operazioni di sommae moltiplicazione su oggetti di un ipotetico tipo Complex
Dobbiamo realizzare un ADT che rappresenti il numerocomplesso e fornire metodi per la somma, la moltiplicazione, etc.
41 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Numeri Complessi
Un Numero complesso è formato da due parti, la parte reale e laparte Immaginaria, nella forma a+bi
i =√−1 è un numero immaginario, i2 = 1
Per la moltiplicazione usiamo le usuali regole
(a+bi)(c +di) = ac +bci +adi +bdi2 = (ac−bd)+(ad +bc)i
Esistono numeri complessi che restituiscono 1 quando elevati aduna certa potenza. Questi numeri sono detti radici complessedell’unità.
Per ogni intero N esistono N complessi z per cui zN = 1. I numeri:
cos
(2πkN
)+ i sin
(2πkN
)k = 0,1, . . . ,N−1
posseggono questa proprietà
42 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di applicazione
L’applicazione deve calcolare le N radici dell’unità ed elevareciascuna di esse all’N-esima potenza (ottenendo sempre 1)Sorge il problema di moltiplicare i numeri complessi. Duepossibilità
metodo statico che accetti come argomenti due complessimetodo che fa parte dell’interfaccia dell’ADT Complex cheaccetta un solo metodo
AttenzioneLa seconda soluzione è da preferire perchè non alloca un nuovoComplex ogni volta
43 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di applicazione
Se t è un Complex ci aspettiamo di poter scrivere:Complex z = t; for (int j = 0; j<N-1;j++) z.mult(t);
ma z e t sono riferimenti allo stesso oggetto e quindi in effettistiamo commettendo un errore e calcolando t2N
e non tN comedovuto.
44 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di applicazione
Programma radici dell’unità
public class RootsOfUnity{
public static void main(String[] args){ int N = Integer.parseInt(args[0]);
Out.println(N + " roots of unity");for (int k = 0; k < N; k++)
{ double x = Math.cos(2.0*Math.PI*k/N),
y = Math.sin(2.0*Math.PI*k/N);
Complex t =new Complex(x, y);
Out.print(k + ": "+ t);Complex z = (Complex) t.clone();for (int j = 0; j < N-1; j++)
z.mult(t);Out.println(" " + z);
}}
}
Interfaccia per Complex
class Complex implements Cloneable{ // implementations
// and private members hiddenComplex(double re, double im)double re()double im()Complex mult(Complex rhs)public Object clone()public String toString()
}
45 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Esempio di applicazione
Implementazione dell’ADT Complex
class Complex implements Cloneable{
private double re, im;Complex(double re, double im)
{ this.re = re; this.im = im; }double re()
{ return re; }double im()
{ return im; }void add(Complex rhs)
{re = re() + rhs.re();im = im() + rhs.im();
}void mult(Complex rhs)
{ double t = re();re = re() * rhs.re() - im() * rhs.im();im = t * rhs.im() + im() * rhs.re();
}public String toString()
{ return re() + " " + im(); }}
Come abbiamo visto finoral’implementazione èformata da:
Interfaccia dell’ADT
Implementazionedell’ADT
Programma client
46 / 48
IntroduzioneADT StackCode FIFO
Esempio di ApplicazioneConclusioni
Prospettive
Gli ADT sono uno strumento importante di Ingegneria del Software
consentono l’uso di diversi livelli di astrazione
aiutano ad incapulare gli algoritmi in modo da facilitarne il riuso
forniscono un meccanismo utile per confrontare tra loroimplementazioni e/o programmi client
Plausibilmente ogni situazione solleva necessità particolari quindi nonè opportuno pensare a ADT che risolvano tutte le situazioni possibili
Chi implementa ADT deve conoscere le necessità lato client
Chi implementa applicazioni deve conoscere le differenze traADT (in termini di operazioni, loro comportamento e prestazioni)
47 / 48