Lezione XXXIII Me 23-Nov-2005
Esercitazione
Una coda ordinata (CO) è definita dalla seguente classe:
// CO.java --coda ordinata public class CO{ /* parte privata della classe */
public CO() {...} public void accoda(Comparable x) {...} public Object togli() {...}
nella quale il metodo accoda(x) inserisce l'oggetto x (che realizza l'interfaccia Comparable) nella coda in modo tale che il metodotogli() restituisca sempre l'oggetto più piccolo presente nella coda
Il metodo vuota() restituisce un booleano vero se la coda è vuota, falso se la coda contiene oggetti. Il costruttore CO() crea una coda ordinata vuota.
Completare la classe CO con la parte privata e con il codice cherealizza i metodi e il costruttore
La classe CO non deve avere altri metodi pubblici oltre a quellidefiniti sopra
Scrivere una classe Main di prova che:
Il metodo togli() deve restituire sempre l’oggetto piu’ piccolo presente nella coda
Per questo ci sono due soluzioni possibili:
A.Il metodo accoda() non si cura dell’ordinamento degli oggetti,mentre il metodo togli() esegue la ricerca del minimoscandendo tutta la coda.
– In questo caso possiamo realizzare, al meglio, i metodi accoda() e togli() con andamenti asintotici O(1) e O(n), rispettivamente.
66
B.Il metodo accoda() inserisce l’oggetto in modo da mantenere ordinato l’insieme dei dati, mentre il metodo togli() restituisce l’oggetto piu’ piccolo
Scegliamo come contenitore la struttura dati catena
Il metodo accoda() mantenga i dati ordinati in sensocrescente in modo che il dato piu’ piccolo si trovi nel primo nodo
Il metodo togli() restituisce il dato contenuto nel primonodo
Realizziamo la classe Nodo come classe interna della classe CO
Scegliamo come contenitore la struttura dati arrayriempito parzialmente
Il metodo accoda() mantenga i dati ordinati in sensodecrescente in modo che il dato piu’ piccolo si trovi nella locazione di indice arraySize -1
Il metodo togli() restituisce il dato contenuto nellalocazione di indice arraySize -1
74
import java.io.IOException;import java.io.FileReader;import java.util.Scanner;
public class MainCO{ public static void main(String[] args)
{ throws IOException// Verifica argomenti su riga di comando
if(args.length < 1){ System.out.println(
"uso: $java MainCO nomeFile");return;}
// lettura file Scanner in = new Scanner( new FileReader(args[0])); CO storeCO = new CO();
while (in.hasNextLine()){ Scanner tok = new Scanner(in.nextLine());
while (tok.hasNext()) storeCO.accoda(tok.next()); } tok.close();
in.close();
78
79
Usare un file di prova come file di ingresso, ad esempio un file come i seguenti
Inserire in punti chiave del codice istruzioni di stampa a standard output per il debugging
– ad esempio nel motodo accoda(), dopo l’inserimento del dato, si stampino il valore della variabile objSize e i dati ordinati
//Inserimento nell’array
obj[i] = x;
objSize++;
//System.out.println(“objSize = “
Esercitazione
Traduttore Per tradurre in modo elementare un testo dall'italiano in inglese e viceversa si vuole realizzare la seguente classe:
// TR.java --traduttore
public class TR{ /* parte privata della classe */ … public TR(String nomeFile) {...} public String inInglese(String parolaItaliana) {...}
} public String inItaliano(String parolaInglese) {...}
Esercitazione
nella quale il metodo "inInglese(x)" restituisce la parolainglese corrispondente alla parola italiana x
analogamente il metodo "inItaliano(x)" restituisce la parola italiana corrispondente alla parola x inglese.
Nel caso non sia disponibile la traduzione della parolacercata i due metodi restituiscono un puntatore "null".
Il costruttore "TR(nomeFile)“ preleva dal file di testo"nomeFile" le coppie
Le coppie sono riportate sul file una per riga e le parolesono separate da uno spazio bianco, sappiamo che ogniparola compare una volta sola nel file e che non ci sonoparole italiane uguali a parole inglesi e viceversa.
Esercitazione
Completare la classe TR con la parte privata e con il codice che realizza i due metodi e il costruttore.
Nella realizzazione della classa TR non è consentito utilizzare classi "contenitore" quali Collections, HashSet, Hashtable, Vector, LinkedList, ecc. delle librerie di Java.
Scrivere una classe Main di prova che, creato un esemplare della classe TR, legga dall'ingresso standard un testo in italiano e lo traduca in inglese scrivendo il risultato sull'uscita standard
Nel caso una parola italiana non possa essere tradotta il programma di prova dovrà riportare nella traduzione la parola italiana originaria preceduta e seguita da un asterisco.
Soluzione minima
// TR.java --traduttore // soluzione elementare: ricerca per// scansione di un vettore;import java.io.*;import java.util.*;
public class TR{ class Coppia{ String italiano;
String inglese;
Coppia (String it, String en)
{ italiano = it; inglese = en;) }
}// parte privata
private Coppia[] v;
private int n;
public TR(String nome) throws IOException
{ v = new Coppia[1000]; // array dim. fissa
Scanner in = new Scanner(new FileReader(nome));
while (in.hasNextLine()){ Scanner tok = new Scanner(in.nextLine());v[n] = new Coppia(tok.next(), tok.next());n++;
} }in.close();tok.close();
FileNotFoundException sottoclasse di IOException
Soluzione minima
public String inItaliano(String x){ for (int i = 0; i < n; i++)
if (x.compareTo(v[i].inglese) == 0) return v[i].italiano; return null; }
public String inInglese(String x){ for (int i = 0; i < n; i++)
if (x.compareTo(v[i].italiano) == 0)return v[i].inglese;
return null;}} // Fine della classe
// TR1.java --traduttore // soluzione efficiente realizzata con una// tabella hashimport java.io.*;import java.util.*;public class TR1{ class Nodo
{ String chiave; String attributo; Nodo prossimo;
Nodo (String c, String a, Nodo p) { chiave = c; attributo = a; } } prossimo = p;
// parte privata private Nodo[] v; private static final int MAX = 97;
private int h(String ch){ int n = 0;
for (int i = 0; i < ch.length(); i++) n = ((31 * n) + ch.charAt(i)) % MAX;
return n; }
public TR1(String nome) throws IOException
{ v = new Nodo[MAX];Scanner in = new Scanner(new FileReader(nome));while (in.hasNextLine()){ Scanner tok = new Scanner(in.nextLine());
String italiano = tok.next(); String inglese = tok.next(); int chr = h(italiano); v[chr] = new Nodo(italiano, inglese, v[chr]); chr = h(inglese); v[chr] = new Nodo(inglese, italiano, v[chr]);
} }in.close();tok.close();
FileNotFoundException sottoclasse di IOException
public String inItaliano(String x){ Nodo p = v[h(x)];
while (p != null) if (x.compareTo(p.chiave) == 0) return p.attributo; else p = p.prossimo;
return null; }
public String inInglese(String x){
} return inItaliano(x);
} // fine della classe
Soluzione con doppia tabella hash
// TR2.java --traduttore // soluzione efficiente realizzata con due// tabelle hashimport java.io.*;import java.util.*;public class TR2{ class Nodo
{ … }
private Nodo[] inInglese;private Nodo[] inItaliano;private static final int MAX = 11;
private int h (String ch) { … }
public TR2(String nome) throws IOException{ inItaliano = new Nodo[MAX];inItaliano = new Nodo[MAX];
Scanner in = new Scanner(new FileReader(nome)); while (in.hasNextLine()) { Scanner tok = new Scanner(in.nextLine());
String italiano = tok.next(); String inglese = tok.next(); int chr = h(italiano); inInglese[chr] = new Nodo(italiano,
inglese, inInglese[chr]); chr = h(inglese); inItaliano[chr] = new Nodo(inglese,
italiano, inItaliano[chr]);} }in.close();tok.close();
FileNotFoundException sottoclasse di IOException
public String inItaliano(String x){ Nodo p = inItaliano[h(x)];
while (p != null) if (x.compareTo(p.chiave) == 0) return p.attributo; else p = p.prossimo; return null;
}public String inInglese(String x){ Nodo p = inInglese[h(x)];
while (p != null) if (x.compareTo(p.chiave) == 0) return p.attributo; else p = p.prossimo; return null;
import java.io.IOException;import java.util.Scanner;
public class Main{ public static void main(String[] arg) throws IOException{ Scanner in = new Scanner(System.in);TR2 diz = new TR2(arg[0]);
while (in.hasNext())
{ String parola = in.next(); String traduzione = diz.inInglese(parola); if (traduzione == null)
System.out.print("*" + parola + "* ");else System.out.print(traduzione + " ");} } }in.close();System.out.println();
File di ingreso di prova
Lezione XXXIV Gi 24-Nov-2005
ADT Set Standard Error
Il flusso di errore standard
Abbiamo visto che un programma Java ha sempre due flussi ad esso collegati
– il flusso di ingresso standard, System.in
– il flusso di uscita standard, System.out che vengono forniti dal sistema operativo In realtà esiste un altro flusso, chiamato flusso di
errore standard o standard error, rappresentato dall’oggetto System.err
– System.err è di tipo PrintStream come System.out
Il flusso di errore standard
La differenza tra System.out e System.err è solo convenzionale
Il flusso di errore standard
In condizioni normali (cioè senza redirezione) lo standard error finisce sullo schermo insieme allo standard output
In genere il sistema operativo consente di effettuare la redirezione dello standard error in modo indipendente dallo standard output
ADT Set Realizzazione di un insieme
Insieme
Il tipo di dati astratto “insieme” (set) è un contenitore (eventualmente vuoto) di oggetti distinti (cioè non contiene duplicati)
Le operazioni consentite sull’insieme sono
Non esiste un’operazione di rimozione
– si usa la sottrazione tra insiemi (vedi in seguito)
Operazioni sugli insiemi
Per due insiemi A e B, si definiscono le operazioni
Insieme con array non ordinato
Quando si scrive una classe, è comodo scrivere prima le firme di tutti i metodi, con un corpo “vuoto”
Invece di compilare tutto alla fine, si compila ogni volta che si scrive il corpo di un metodo
– in questo modo, si evita di trovarsi nella situazione in cui il compilatore segnala molti errori
Insieme con array non ordinato
Operazioni su insiemi: unione
Insiemi: intersezione e sottrazione
Insieme con array non ordinato
Riassumendo, realizzando un insieme con un array non ordinato
– le prestazioni di tutte le primitive dell’insieme sono O(n)
– le prestazioni di tutte le operazioni che agiscono su due insiemi sono O(n2) Si può facilmente verificare che si ottengono le stesse
prestazioni realizzando l’insieme con una catena (prestazioni determinate dalla ricerca)
Insieme di dati ordinabili
Cerchiamo di capire se si possono ottenere prestazioni migliori quando l’insieme contiene dati ordinabili
Definiamo l’interfaccia “insieme ordinato”
Insieme di dati ordinabili
Realizziamo l’interfaccia SortedSet usando un array ordinato
– dovremo definire due metodi add(), uno dei quali
impedisce l’inserimento di dati non ordinabili
Insieme con array ordinato
Operazioni su insiemi ordinati
Gli algoritmi già visti per le operazioni sugli insiemigenerici possono essere utilizzati senza alcunamodifica anche per l’insieme ordinato, realizzatocon un array ordinato
Senza sfruttare le informazioni sull’ordinamento dell’insieme, non è possibile ottenere prestazionimigliori...
Operazioni su insiemi ordinati
Usare l’incapsulamento a oltranza può essere sconveniente…
In questo caso, sapendo che
è possibile scrivere versioni più efficienti dei metodi già visti
Per realizzare l’unione, osserviamo che il problema è molto simile alla fusione di due array ordinati
– come abbiamo visto in MergeSort, questo algoritmo di fusione è O(n)
L’unica differenza consiste nella contemporanea eliminazione (cioè nel non inserimento…) di eventuali oggetti duplicati
– un oggetto presente in entrambi gli insiemi dovrà essere presente una sola volta nell’insieme unione
Effettuando la fusione dei due array ordinati secondo l’algoritmo visto in MergeSort, gli oggetti vengono via via inseriti nell’insieme unione che si va costruendo
Se gli inserimenti avvengono con oggetti in ordine crescente, l’ordinamento per inserzione in un array ordinato che viene usato dal metodo add() ha prestazioni O(1) per ogni inserimento!
Operazioni su insiemi: unione
Operazioni su insiemi: sottrazione