Argomenti della lezione
Tipi di dato astratti
Strutture dati elementari
• Liste
—Implementazione di liste in Java
• Stack
• Code
Esempi di applicazione
1
Tipo di dato astratto
Tipo di dato astratto o ADT (Abstract Data Type):
insieme di oggetti e insieme di operazioni definite su
di esso
Es.: lista con operazioni di inserimento e
cancellazione
Attenzione: l’ADT specifica cosa fa ogni operazione,
non come
In Java:
Rappresentazione con interfaccia
Implementazione con classe
2
Liste in Java/2
Interfaccia List
Rappresenta una collezione ordinata di
elementi
Ammette duplicati
Implementazioni: classi LinkedList,
ArrayList e Vector
10
Liste in Java/3
Classe LinkedList
Classe ArrayList
Realizza una lista
Realizza lista mediante
doppiamente
concatenata
Puntatori a inizio e fine
della lista
array
Dimensione puo’ essere
variata dinamicamente.
11
Classe LinkedList
LinkedList: realizza una lista come generica lista
doppiamente concatenata.
Costruttore
•
LinkedList LinkedList(): costruttore
Metodi principali:
•
•
•
•
•
•
•
•
•
void add(Object o): inserisce alla fine della lista
void addFirst(Object o): inserisce in testa alla lista
Object removeFirst(): elimina all’inizio della lista
Object removeLast(): elimina alla fine della lista
Object remove(int pos): rimuove l’oggetto in posizione pos
Object getFirst(): restituisce il primo oggetto
Object getLast(): restituisce l’ultimo oggetto
Object get(int pos): restituisce l’oggetto in posizione pos
Iterator iterator(): restituisce un Iterator sulla lista
12
Classe ArrayList
Corrisponde all’implementazione con array
Costruttore
• ArrayList ArrayList() : costruisce
lista vuota
Metodi principali:
• Simili a quelli di LinkedList
• Fornisce anche metodi per la modifica
delle dimensioni dell’array
13
Iteratori
Sono oggetti che implementano l’interfaccia
Iterator
Servono a scorrere sequenzialmente oggetti
di tipo Collection (quindi anche liste)
Esempio:
...
LinkedList myList = new LinkedList();
....
Iterator myIterator = myList.iterator();
14
Iteratori/2
myIterator permette di scorrere gli elementi di
myList
Metodi:
• Object next(): restituisce l’elemento successivo della
lista
• boolean hasNext(): vero se la lista contiene altri
elementi
• void remove(): elimina dalla lista l’elemento corrente
E’ solamente un oggetto di ausilio per scorrere la lista
Si può ovviamente scorrere la lista direttamente
usando gli indici
15
Classe Vector
E’ simile ad ArrayList
I metodi sono simili a quelli di
ArrayList
E’ una classe sincronizzata
• E’ consigliabile usarla quando più thread
che accedono alla stessa struttura dati
16
Classe Vector/2
Array:
Classe Vector
Possono contenere tipi
Contiene Object. I tipi di dati
di dati primitivi
Dimensione fissa
Pochi metodi ma
maggiore efficienza
primitivi devono essere
convertiti mediante gli
opportuni wrapper.
Gestione flessibile dello
spazio di memoria.
Gran numero di metodi a
scapito dell'efficienza
17
Esempi di uso della classe Vector e
dell’interfaccia Iterator
......
Vector v = new Vector();
String st = br.readLine(); // br BufferedReader
while (st != null) {
v.addElement(st);
st = br.readLine();
}
System.out.println();
Iterator it = v.iterator();
while (it.hasNext())
System.out.println(it.next());
......
18
Vector di tipi di dato primitivi
.......
Vector v = new Vector();
String st = br.readLine(); // br BufferedReader
while (st != null) {
int num = Integer.parseInt(st);
v.addElement(new Integer(num));
st = br.readLine();
}
System.out.println();
Iterator it = v.iterator();
while (it.hasNext())
System.out.println(it.next());
........
19
Tipo astratto Pila
Lista nella quale inserimenti e cancellazioni avvengono solo in testa
(disciplina LIFO).
Operazioni sempre presenti
•
push(el): inserisce l'elemento specificato da el in cima alla pila
•
pop(): elimina l'elemento in cima alla pila
•
top(): restituisce l'elemento in cima alla pila senza cancellarlo dalla
lista
•
isEmpty(): verifica se la pila è vuota
Altre operazioni
•
clear(): elimina tutti gli elementi dalla pila
20
Implementazione del tipo Pila
Realizzazione tramite Array
Ai
top = i
A1
A0
Liste: realizzazione tramite lista concatenata
top
Start
A0
A1
Ai
AN
21
Implementazione Java con Vector
public Object topEl(){
return
pool.lastElement();
}
public Object pop(){
return
pool.remove(pool.size()-1);
}
public void push(Object el){
pool.addElement(el);
}
public class Stack {
private java.util.Vector
pool=
new java.util.Vector();
public Stack(){
}
public Stack(int n){
pool.ensureCapacity(n)
}
public void clear(){
pool.clear();
}
public boolean isEmpty(){
return pool.isEmpty();
}
}
22
Implementazione tramite LinkedList
public class LLStack {
private list= new
java.util.LinkedList();
public LLStack(){
}
public void clear(){
list.clear();
}
public boolean isEmpty(){
return list.isEmpty();
}
public Object topEl(){
return list.getLast();
}
public Object pop(){
return list.removeLast();
}
public void push(Object el){
list.add(el);
}
public String toString(){
return list.toString();
}
}
Attenzione: java.util.Stack
non realizza una vera pila (ci
sono operazioni in più)
23
Tipo astratto coda
Lista nella quale gli inserimenti avvengono in coda e
le cancellazioni (estrazioni) in testa (disciplina FIFO)
Operazioni sempre presenti
• isEmpty(): verifica se la coda è vuota
• enqueue(el): inserisce l'elemento specificato
da el alla fine della coda
• dequeue(): elimina il primo elemento della coda
• firstEl(): restituisce il primo elemento della
coda senza eliminarlo
Altre operazioni
• clear(): elimina tutti gli elementi dalla coda
25
Implementazione di code con array
A0
A1
A2
AN-3 AN-2 AN-1
testa
coda
Elemento non usato
enqueue -> coda = coda + 1 (mod N)
dequeue -> testa = testa + 1 (mod N)
Se (coda == testa – 1 mod N) coda piena
Se (coda == testa) coda vuota (un solo elemento
presente)
26
Implementazione di coda con
Array circolare
first:
last:
size:
indice del primo elemento - testa
indice dell'ultimo - coda
numero di elementi dell'array
public class ArrayQueue {
private int first, last, size;
private Object[] storage;
private static final int DEFAULTSIZE = 100;
// metodi nella prossima slide
27
Implementazione di coda con
Array circolare/2
public ArrayQueue(){
this(DEFAULTSIZE);
}
public ArrayQueue(int n){
size = n;
storage = new Object[size];
first = last = -1;
}
public boolean isFull(){
return ((first == 0) && (last == size - 1)) ||
(first == last + 1);
}
public boolean isEmpty(){
return first == -1;
}
Algoritmi e strutture dati
28
Implementazione di coda con
Array circolare/3
public void enqueue(Object el){
if(!isFull())
if ((last == size - 1) || (last == -1)) {
storage[0] = el; last = 0;
if (first == -1) //caso coda vuota
first=0;
} else storage[++last] = el;
}
29
Implementazione di coda con
Array circolare/4
public Object dequeue(){
Object tmp = null;
if(!isEmpty()) {
tmp = storage[first];
if (first == last) // caso unico elemento
last = first = -1;
else if (first == size - 1)
first = 0;
else first++;
}
return tmp; // Restituisce null se coda vuota
}
30
Implementazione di coda con
Array circolare/5
public void printAll(){
if(isEmtpy())
System.out.println("Coda vuota.");
else {
int i = first;
do {
System.out.print(storage[i] + " ");
i = (i + 1) % size;
} while(i != ((last + 1) % size));
System.out.println();
}
}
} // fine classe ArrayQueue
31
Implementazione di una coda
con lista concatenata
public class QueueNode {
protected Object info;
protected QueueNode next = null;
public QueueNode(Object el) {
info = el;
}
}
public class Queue {
private QueueNode head, tail;
public Queue() {
head = tail = null;
}
32
Implementazione di una coda
con lista concatenata/2
public boolean isEmpty() {
return head == null;
}
public void clear() {
head = tail = null;
}
public Object firstEl() {
return head.info;
}
33
Implementazione di una coda
con lista concatenata/3
public void enqueue(Object el) {
QueueNode q = new QueueNode(el);
if (!isEmpty()) {
tail.next = q;
tail = tail.next;
} else head = tail = q;
34
Implementazione di una coda
con lista concatenata/4
public Object dequeue() {// cancella il nodo in
// testa e restituisce il campo info
if (!isEmpty()) {
Object el = head.info;
if (head == tail) // un solo nodo?
head = tail = null;
else head = head.next;
return el;
} else return null;
} // fine metodo dequeue
} // fine classe Queue
35
Riconoscimento di stringhe
parenteticamente corrette
La stringa vuota è parenteticamente corretta
Se P1, P2 e P3 sono corrette, allora lo è anche
P1(P2)P3, P1[P2]P3 o P1{P2}P3
Es.:
• ab(ax)[(b)du{(mb)}] è corretta
• a(ax)[c e a){b(e} non sono corrette
36
Algoritmo (solo un tipo di parentesi)
Algorithm stringAnalyzer
balanced = true;
S = <Leggi la stringa>
c = <primo carattere di S>
count = 0;
while ((! <fine di S>) && (count
>= 0)) {
if (c == ‘(’)
count++;
else if (c == ‘)’)
count--;
c = <prossimo carattere di
S>
}
if ((fine di S) && (count != 0))
balanced = false;
Provare a implementare
il riconoscimento con
parentesi di
qualunque tipo.
Es.:
- fg{([{ab(vc)g}kj])} è
corretta
- gh{(df[ghj]}gh)hj non
è corretta
37
Algoritmo (caso generale)
Usa uno stack
Se arriva ‘(‘, ‘[‘ o ‘{‘
inseriscila nello stack
Se arriva ‘)‘, ‘]‘ o ‘}‘
confrontala con l’elemento
affiorante
• Se non corrispondono allora la
)
(
]
[
(
stringa non è bilanciata
Se si esamina la stringa fino
alla fine e lo stack non è
vuoto la stringa non è
bilanciata. Es.: (((er[])
38