Sei sulla pagina 1di 12

Lista con posizione astratta

Lista con posizione astratta


Usando una struttura lineare concatenata (catena o linked
list), facile realizzare una lista che rappresenti la posizione dei
dati al proprio interno tramite un concetto astratto, che non sia
un numero come un indice ma un oggetto pi complesso
Basta usare il nodo che, nella catena, contiene un dato come
rappresentazione astratta della posizione del dato stesso
Esclusi i casi degeneri (primo e ultimo), ciascun nodo ha un nodo
precedente e un nodo successivo, proprio come una posizione
Cos facendo, per
si vincola la realizzazione dellADT a una particolare
struttura interna, che usi un particolare tipo di nodo (ad
esempio, singolo o doppio ?)
si espone il nodo a manipolazioni dirette dallesterno,
che magari rompono la catena
Posizione in una lista
Meglio definire un concetto astratto di posizione
mediante unapposita interfaccia
Che comportamento deve avere una posizione allinterno di una
lista? Deve identificare univocamente un dato della lista, allo
scopo di consentire la sua ispezione
public interface Position<T>
Sarebbe stato meglio chiamarlo { T element();
getElement() }
Una posizione non un ADT di tipo contenitore
In realt anchesso un contenitore, ma pu contenere un solo
dato quindi non appartiene alla generica categoria degli ADT di
tipo contenitore
Infatti non estende Container, non ha il metodo isEmpty n
size
Problemi di
nomenclatura
Posizione in una lista
public interface Position<T>
{ T element(); }
Una lista con posizione astratta (spesso detta lista) ,
quindi, un contenitore che memorizza ciascun dato in una
diversa posizione, per ognuna delle quali definita una
posizione precedente e una posizione successiva
La prima posizione non ha precedente e lultima non ha successiva
Notiamo che SLLNode e DLLNode, i nodi delle catene,
realizzano gi questa interfaccia (perch hanno gi il metodo
Visti nel getElement), basta che aggiungiamo loro la relativa
ripasso clausola implements e inseriamo un metodo stub
public class SLLNode<T> implements Position<T>
{ ...
T element() { return getElement(); } // stub
}
Lista con posizione astratta
A questo punto possiamo definire un ADT PositionalList che
rappresenti il comportamento di una lista (cio di una collezione di dati tra i
quali esiste una relazione posizionale di tipo precedente/successivo) nella
quale la posizione di ciascun dato sia rappresentata in modo astratto da un
esemplare di una classe (ad esempio, SLLNode o DLLNode) che
implementi linterfaccia Position
fondamentale che le posizioni siano esemplari di una classe
PRIVATA, INTERNA alla lista, altrimenti chi le riceve sotto forma di
riferimento di tipo Position pu fare un down-casting e ottenere
loggetto (ad esempio, il nodo), per poi manipolarlo e non va bene!
A volte PositionalList viene chiamata NodeList
Ha metodi che consentono di navigare da una posizione
allaltra e metodi che consentono di
modificare/inserire/ispezionare/rimuovere dati
Lista con posizione astratta
public interface PositionalList<T> extends Container
{ // metodi di navigazione tra le posizioni
Position<T> first()
throws EmptyListException;
Position<T> last()
throws EmptyListException;
Position<T> prev(Position<T> p)
throws InvalidPositionException,
BoundaryViolationException;
Position<T> next(Position<T> p)
throws InvalidPositionException,
BoundaryViolationException;
// metodi di modifica del contenuto della lista
...
}

Si osservi che nella definizione di questo ADT non c


nessun riferimento esplicito al concetto di nodo
Si pu realizzare concretamente anche usando un array
(ma in tal caso non molto efficiente)
Lista con posizione astratta
public interface PositionalList<T> extends Container
{ // metodi di navigazione tra le posizioni
... // quelli appena visti
// metodi di modifica del contenuto della lista
void addFirst(T element);
void addLast(T element);
void addBefore(Position<T> p, T element)
throws InvalidPositionException;
void addAfter(Position<T> p, T element)
throws InvalidPositionException;
T set(Position<T> p, T element)
throws InvalidPositionException;
T remove(Position<T> p)
throws InvalidPositionException;
}
Lista con posizione astratta
Non ha un metodo get per ispezionare i dati
ma che parametro potremmo fornirgli? Sarebbe
T get(Position<T> p)
throws InvalidPositionException;
Per invocare get ci serve una posizione ma, avendo
una posizione, inutile invocare get, basta invocare
element sulla posizione stessa!
Quindi, per accedere a un elemento si invoca
first o last e si naviga (next/prev) fino
alla posizione che interessa, poi si invoca
element sulla posizione
Lista con posizione astratta
I metodi prev(p)/next(p) lanciano
BoundaryViolationException se
p == first()/p == last()
Apparentemente il metodo addFirst(e) ridondante
Si potrebbe svolgere la stessa funzione invocando
addBefore(first(), e) ?
S, ma soltanto in una lista NON vuota, perch in una
lista vuota linvocazione di first provoca il lancio di
uneccezione: in tal caso necessario invocare
addFirst
Analogamente, il metodo addLast(e) si pu sostituire
con addAfter(last(), e), tranne quando la lista
vuota
Lista con posizione astratta
Un esemplare di Position rappresenta la posizione di
un particolare dato allinterno della lista, non una
particolare posizione (cio non la terza posizione)
Questo significa che, dopo linvocazione di remove(p), la posizione
p non pi valida, in quanto non esiste pi nella lista un dato in quella
posizione (proprio perch stato rimosso)
Due invocazioni di remove con la stessa posizione provocano il
lancio di InvalidPositionException
Al contrario, in una lista con indice/rango,
ciascun indice/rango associato a una posizione
(la terza cella) e non a un dato
Inserendo un dato con indice k,
il dato che aveva indice k viene ad avere indice k + 1
Realizzazione di PositionalList
abbastanza naturale realizzare una PositionalList
mediante una struttura a nodi (doppiamente) concatenati,
assai simile a una catena doppia
public class DLinkedListPositionalList<T>
implements PositionalList<T>
{ private class DLLNode<T> implements Position<T>
{ ... } // gi vista nel ripasso autonomo
private DLLNode<T> head, tail;
private int size;
public DLinkedListPositionalList() // crea lista vuota
{ size = 0;
head = new DLLNode<T>();
tail = new DLLNode<T>();
head.setNext(tail);
tail.setPrev(head);
} // si pu fare anche senza nodi header/trailer
// ma pi complicato (pur con stesse prestazioni)
...
}
Realizzazione di PositionalList
abbastanza naturale realizzare una PositionalList mediante
una struttura a nodi (doppiamente) concatenati, assai simile a una
catena doppia
public class DLinkedListPositionalList<T>
implements PositionalList<T>
{ ...
public Position<T> first()
{ if (isEmpty()) throw new EmptyListException();
return head.getNext(); /* restituisce un esemplare
di DLLNode, che valido come Position */
}
private DLLNode<T> checkPosition(Position<T> p)
{ /* una posizione valida ?? */ }
...
}

Non si pu realizzare con analoga efficienza


incapsulando una catena perch?