Gli array permettono di rappresentare sequenze indicizzate di elementi
Gli insiemi sono diversi:
Possiamo rappresentare insiemi usando array
memorizzo gli elementi nel vettore
Devo tenere presente le caratteristiche dei vettori:
Soluzione: incapsulamento!
Da questo, ricavo la definizione dei metodi della classe
Per insiemi di interi:
Manca un modo per fare la scansione dell'insieme
Per ora, mettiamo solo un metodo di stampa
Ogni volta che devo inserire un elemento, creo un nuovo array, più grande di uno
Ogni volta che elimino un elemento, creo un nuovo vettore, più piccolo
La classe si presenta in questo modo:
class Insieme { private int elementi[]; Insieme() { ... } void stampa() { ... } boolean verificaVuoto() { ... } boolean presente(int x) { ... } void inserisci(int x) { ... } void elimina(int x) { ... } }
Implementiamo i metodi uno per volta
Deve creare l'insieme vuoto
È il vettore che ha zero elementi
Insieme() { this.elementi=new int[0]; }
Domanda: this.elementi=null è lo stesso?
Non sono la stessa cosa:
Con new si crea comunque un oggetto, anche se poi non ha nessuna componente
Vantaggio: posso usare this.elementi.length se this.elementi è l'array vuoto
Se this.elementi è null, allora non esiste nemmeno la componente length
Devo stampare il vettore
void stampa() { int i; for(i=0; i<this.elementi.length; i++) System.out.println(this.elementi[i]); }
Se l'insieme vuoto lo rappresento con null:
this.elementi era null
Quindi, this.elementi.length è un errore
Invece l'array vuoto ha this.elementi.length==0.
La condizione è subito falsa, e non si esegue mai il corpo del ciclo
L'insieme è vuoto se l'array ha zero elementi
boolean verificaVuoto() { return this.elementi.length==0; }
Faccio la scansione del vettore
boolean presente(int x) { int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i]==x) return true; return false; }
Devo tenere presente che:
Soluzione:
Per controllare se l'elemento sta già nell'insieme, posso usare il metodo presente
void inserisci(int x) { if(this.presente(x)) return; // aggiungi l'elemento }
L'array attuale ha dimensione this.elementi.length
Ne creo uno più grande di uno:
void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; // copia e aggiungi }
Tutti gli elementi del vecchio array vanno nel nuovo:
void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; int i; for(i=0; i<this.elementi.length; i++) nuovo[i]=this.elementi[i]; // aggiungi }
Cosa succede se faccio direttamente:
void inserisci(int x) { if(this.presente(x)) return; this.elementi=new int[this.elementi.length+1]; // }
Il nuovo vettore viene creato vuoto
(tutti gli elementi sono zero)
Ho perso il riferimento al vecchio array
non posso più copiare i vecchi elementi
Il nuovo array ha una posizione libera (l'ultima)
Ci metto il nuovo elemento
void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; int i; for(i=0; i<this.elementi.length; i++) nuovo[i]=this.elementi[i]; nuovo[nuovo.length-1]=x; // e ora? }
Situazione attuale:
Situazione che voglio ottenere:
Dal confronto: in this.elementi voglio l'indirizzo del nuovo array
L'indirizzo del nuovo array sta in nuovo
Basta fare this.elementi=nuovo;
void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; int i; for(i=0; i<this.elementi.length; i++) nuovo[i]=this.elementi[i]; nuovo[nuovo.length-1]=x; this.elementi=nuovo; }
Devo creare un nuovo vettore, più piccolo di uno
int nuovo[]; nuovo=new int[this.elementi.lenght-1];
Esempio:
Posso fare la copia come prima?
Non funziona se l'elemento da eliminare non è l'ultimo
Soluzioni?
for(i=0; i<...; i++) if(this.elementi[i]!=x) nuovo[i]=this.elementi[i];
L'unica cosa che fa è lasciare vuota la posizione in cui stava prima l'elemento da eliminare
Se il ciclo arriva ad i=nuovo.length-1, l'ultimo non viene copiato.
Se arriva fino a i=nuovo.length, si usa nuovo[i] che non esiste
Ora posso fare la copia nell'array nuovo
Prima, controllo se l'elemento c'è:
void elimina(int x) { if(!this.presente(x)) return; // copia }
Faccio un ciclo di copia
Quando trovo l'elemento da eliminare, copio l'ultimo
void elimina(int x) { if(!this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length-1]; int i; for(i=0; i<this.elementi.length-1; i++) if(this.elementi[i]==x) nuovo[i]=this.elementi[this.elementi.length-1]; else nuovo[i]=this.elementi[i]; this.elementi=nuovo; }
Più complicato
Trovo la posizione dell'elemento da eliminare
Copio normalmente tutti quelli prima
Quelli dopo, li copio in una posizione indietro
void elimina(int x) { if(!this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length-1]; int pos=0; int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i]==x) { pos=i; break; } for(i=0; i<pos; i++) nuovo[i]=this.elementi[i]; for(i=pos; i<nuovo.length; i++) nuovo[i]=this.elementi[i+1]; this.elementi=nuovo; } }
Vantaggio: si mantiene l'ordine degli elementi
Nel caso degli insiemi non serve
Si usa un meccanismo di questo tipo se voglio usare gli array per rappresentare sequenze di elementi (non insiemi) in cui l'ordine è importante
Se voglio fare un insieme di stringhe, devo fare un'altra classe
Devo riscrivere tutto, con la sola differenza che == diventa .equals
Ci torneremo
Metodo System.arraycopy
Come si usa:
System.arraycopy(origine, posiniziale, destinazione, posfinale, numero);
Cosa passare:
int v[]=new int[12]; int k[]=new int[12]; System.arraycopy(v, 3, k, 5, 4);
Devo copiare gli elementi dell'array vecchio in quello nuovo
void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length); nuovo[nuovo.length-1]=x; this.elementi=nuovo; }
Copio prima tutti gli elementi.
Poi, al posto di quello da eliminare, ci metto l'ultimo
void elimina(int x) { if(!this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length-1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length-1); int i; for(i=0; i<this.elementi.length-1; i++) if(this.elementi[i]==x) { nuovo[i]=this.elementi[this.elementi.length-1]; break; } this.elementi=nuovo; }
Prima trovo l'elemento da eliminare
Copio in ordine gli elementi prima
Copio gli elementi dopo
void eliminaDue(int x) { if(!this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length-1]; int pos=0; int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i]==x) { pos=i; break; } System.arraycopy(this.elementi, 0, nuovo, 0, pos); System.arraycopy(this.elementi, pos+1, nuovo, pos, this.elementi.length-pos-1); this.elementi=nuovo; }
Da dove viene fuori this.length-pos-1?
Si fa in questo modo:
numero_elem_da_copiare=this.elementi.length-pos+k
Devo solo determinare il numero k
Qui ho
Quindi, 4=6-2+k, ossia k=-1
Rappresenta insiemi di interi
class Insieme { private int elementi[]; Insieme() { this.elementi=new int[0]; } void stampa() { int i; for(i=0; i<this.elementi.length; i++) System.out.println(this.elementi[i]); } boolean verificaVuoto() { return this.elementi.length==0; } boolean presente(int x) { int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i]==x) return true; return false; } void inserisci(int x) { if(this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length+1]; int i; for(i=0; i<this.elementi.length; i++) nuovo[i]=this.elementi[i]; nuovo[nuovo.length-1]=x; this.elementi=nuovo; } void elimina(int x) { if(!this.presente(x)) return; int nuovo[]; nuovo=new int[this.elementi.length-1]; int i; for(i=0; i<this.elementi.length-1; i++) if(this.elementi[i]==x) nuovo[i]=this.elementi[this.elementi.length-1]; else nuovo[i]=this.elementi[i]; this.elementi=nuovo; } }
Esempio: insieme di punti
L'unica cosa che cambia è che == diventa equals
import java.awt.*; class InsiemePoint { private Point elementi[]; InsiemePoint() { this.elementi=new Point[0]; } void stampa() { int i; for(i=0; i<this.elementi.length; i++) System.out.println(this.elementi[i]); } boolean verificaVuoto() { return this.elementi.length==0; } boolean presente(Point x) { int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i].equals(x)) return true; return false; } void inserisci(Point x) { if(this.presente(x)) return; Point nuovo[]; nuovo=new Point[this.elementi.length+1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length); nuovo[nuovo.length-1]=x; this.elementi=nuovo; } void elimina(Point x) { if(!this.presente(x)) return; Point nuovo[]; nuovo=new Point[this.elementi.length-1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length-1); int i; for(i=0; i<this.elementi.length-1; i++) if(x.equals(this.elementi[i])) { nuovo[i]=this.elementi[this.elementi.length-1]; break; } this.elementi=nuovo; } }
Insieme di rettangoli
import java.awt.*; class InsiemeRectangle { private Rectangle elementi[]; InsiemeRectangle() { this.elementi=new Rectangle[0]; } void stampa() { int i; for(i=0; i<this.elementi.length; i++) System.out.println(this.elementi[i]); } boolean verificaVuoto() { return this.elementi.length==0; } boolean presente(Rectangle x) { int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i].equals(x)) return true; return false; } void inserisci(Rectangle x) { if(this.presente(x)) return; Rectangle nuovo[]; nuovo=new Rectangle[this.elementi.length+1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length); nuovo[nuovo.length-1]=x; this.elementi=nuovo; } void elimina(Rectangle x) { if(!this.presente(x)) return; Rectangle nuovo[]; nuovo=new Rectangle[this.elementi.length-1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length-1); int i; for(i=0; i<this.elementi.length-1; i++) if(x.equals(this.elementi[i])) { nuovo[i]=this.elementi[this.elementi.length-1]; break; } this.elementi=nuovo; } }
Insieme di stringhe
import java.awt.*; class InsiemeString { private String elementi[]; InsiemeString() { this.elementi=new String[0]; } void stampa() { int i; for(i=0; i<this.elementi.length; i++) System.out.println(this.elementi[i]); } boolean verificaVuoto() { return this.elementi.length==0; } boolean presente(String x) { int i; for(i=0; i<this.elementi.length; i++) if(this.elementi[i].equals(x)) return true; return false; } void inserisci(String x) { if(this.presente(x)) return; String nuovo[]; nuovo=new String[this.elementi.length+1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length); nuovo[nuovo.length-1]=x; this.elementi=nuovo; } void elimina(String x) { if(!this.presente(x)) return; String nuovo[]; nuovo=new String[this.elementi.length-1]; System.arraycopy(this.elementi, 0, nuovo, 0, this.elementi.length-1); int i; for(i=0; i<this.elementi.length-1; i++) if(this.elementi[i]==x) { nuovo[i]=this.elementi[this.elementi.length-1]; break; } this.elementi=nuovo; } }
A parte il tipo, gli insiemi di oggetti sono identici
Generati (sotto Unix) con:
sed "s,Point,Rectangle,g" InsiemePoint.java > InsiemeRectangle.java sed "s,Point,String,g" InsiemePoint.java > InsiemeString.java
Basta mettere Rectangle oppure String al posto di Point
Per gli oggetti, l'unica differenza è il nome del tipo
Si può definire una classe Insieme generico, che funziona per tutte le classi