Esercizio Si scriva un metodo public Position<E> sibling(Position<E> v) che preso in input un nodo v restituisca il fratello di v. Il metodo dovrà lanciare una BoundaryViolationException nel caso in cui v non abbia un fratello. Strutture Dati Code a Priorità E` un contenitore di oggetti ciascun oggetto possiede una chiave (key) che specifica la priorità dell'oggetto all'interno della collezione la chiave viene generalmente assegnata a un elemento nel momento in cui l'elemento viene inserito e può essere successivamente modificata ad ogni istante può essere rimosso soltanto l'elemento con la più alta priorità Strutture Dati Code a Priorità Per poter stabilire qual è l'oggetto con la più alta priorità è necessario definire una regola per confrontare le chiavi Come deve essere questa regola? deve rendere possibile il confronto fra ogni coppia di chiavi deve stabilire un ordine all'interno della collezione Strutture Dati Code a Priorità Relazione d'ordine è una relazione binaria ≤ su un insieme X che è riflessiva, antisimmetrica e transitiva. proprietà riflessiva: k ≤ k proprietà antisimmetrica: se k ≤ k' e k' ≤ k, allora k = k' proprietà transitiva: se k' ≤ k'' e k'' ≤ k''', allora k' ≤ k''' una relazione d'ordine ≤ si dice totale se k ≤ k' oppure k' ≤ k per ciascuna coppia di elementi k,k' in X se su una collezione è definita una relazione d'ordine totale, allora è ben definito il più piccolo valore della collezione (chiave più piccola) Strutture Dati Code a Priorità l'ADT Coda a Priorità è così definito: E` un contenitore di elementi, ciascun elemento è una coppia (chiave, valore) Metodi principali insert(k,x): inserisce l'elemento con valore x e priorità k removeMin() (o extractMin()): restituisce e rimuove un elemento con la più alta priorità, cioè un elemento con chiave minore o uguale di quella di ogni altro elemento Strutture Dati Code a Priorità Come fare per tenere traccia dell'associazione valore-chiave? composition pattern: un singolo oggetto (entry) è definito come composizione di altri oggetti chiave valore public interface Entry<K, V> { /** Restituisce la chiave memorizzata in questa entry. */ public K getKey(); /** Restituisce il valore memorizzato in questa entry. */ public V getValue(); } Strutture Dati Code a Priorità Come confrontare le chiavi in modo da determinare la più piccola? Strategia 1 implementare una diversa coda a priorità per ogni tipo di chiave e per ogni possibile regola di confronto che si vuole usare Inconveniente: non è molto generale, richiede la riscrittura di molto codice simile Strutture Dati Code a Priorità Come confrontare le chiavi in modo da determinare la più piccola? Strategia 2 le chiavi sono istanze di una classe key che definisce il modo con cui fare il confronto con un opportuno metodo Inconveniente: non esiste un modo unico per confrontare due chiavi. Ci sono contesti in cui l'esito del confronto può essere diverso sulla stessa coppia di chiavi. Esempio: chiavi 4 e 11: 4 ≤ 11 se 4 e 11 sono confrontate numericamente; 11 ≤ 4 se 4 e 11 sono confrontate lessicograficamente; Strutture Dati Code a Priorità Come confrontare le chiavi in modo da determinare la più piccola? comparator pattern: invece di basarci sulle chiavi, per stabilire la regola di confronto definiamo un oggetto comparator (esterno alle chiavi): ogni volta che viene costruita una nuova Coda a Priorità, viene fornito un oggetto Comparator la Coda a Priorità dà la possibilità di definire un nuovo Comparator se il precedente diventa obsoleto Vantaggi: si può dare un'implementazione generale di Coda a Priorità che funziona in una grande varietà di contesti Strutture Dati ADT Coda a Priorità ADT Comparator L'ADT Comparator fornisce un meccanismo di confronto basato sul seguente unico metodo: int compare(E a, E b): restituisce un intero i tale che: i < 0 se a < b; i = 0 se a = b; i > 0 se a > b. Si verifica una condizione di errore se a e b non possono essere confrontati java.util.comparator è l'interfaccia che definisce l'ADT Comparator Strutture Dati ADT Coda a Priorità ADT Comparator (interfaccia java.util.comparator) L'interfaccia java.util.comparator include anche il seguente metodo: ● equals() : confronta un comparatore con un altro comparatore Strutture Dati ADT Coda a Priorità Elenco completo dei metodi Metodi generici ● size() ● isEmpty() ● ● ● ● ● Metodi di accesso min() Metodi di modifica insert(k,x) removeMin() Strutture Dati ADT Coda a Priorità Eccezioni ● ● EmptyPriorityQueueException: lanciato se il metodo min o removeMin viene chiamato su una Coda a Priorità vuota InvalidKeyException: lanciato se il metodo insert(k,x) viene chiamato con una chiave k non valida che rende impossibile il confronto con il Comparator della Coda a Priorità (k null oppure k è di una classe incompatibile con le classi delle altre chiavi) Strutture Dati ADT Coda a Priorità Interfaccia public interface PriorityQueue<K, V> { public int size(); public boolean isEmpty(); /** Restituisce senza rimuoverla una entry con chiave minima. */ public Entry<K,V> min() throws EmptyPriorityQueueException; /** Inserisce una coppia key-value e restituisce la entry creata. */ public Entry<K,V> insert(K key, V value) throws InvalidKeyException; /** Rimuove e restituisce una entry con chiave minima. */ public Entry<K,V> removeMin() throws EmptyPriorityQueueException; } Strutture Dati ADT Coda a Priorità Implementazione con lista non ordinata Gli elementi (k,x) della Coda a Priorità P sono memorizzati in una lista L implementata come lista doppiamente concatenata Caratteristiche: inserimento veloce e cancellazione lenta insert(k,x) richiede tempo O(1) perché possiamo semplicemente creare un nuovo oggetto entry e=(k,x) e usare insertLast(e) min() e removeMin() richiedono tempo O(n) perché richiedono lo scorrimento della lista (non ordinata) per determinare l'elemento con chiave minima Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata Gli elementi (k,x) della Coda a Priorità P sono memorizzati in ordine non decrescente di chiavi in una lista L implementata come lista doppiamente concatenata Caratteristiche: Cancellazione veloce e inserimento lento insert(k,x) richiede tempo O(n) perché bisogna inserire il nuovo oggetto entry e=(k,x) nel posto giusto per mantenere l'ordine non decrescente delle chiavi min() e removeMin() richiedono tempo O(1) perché la chiave minima è all'inizio della lista Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata import java.util.Comparator; public class DefaultComparator<E> implements Comparator<E> { public int compare(E a, E b) throws ClassCastException { return ((Comparable<E>) a).compareTo(b); } } Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata import java.util.Comparator; import nodelist.*; import position.*; public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { protected PositionList<Entry<K,V>> entries; protected Comparator<K> c; /** Classe interna per le entrate della coda a priorita` */ protected static class MyEntry<K,V> implements Entry<K,V> { protected K k; // chiave protected V v; // valore public MyEntry(K key, V value) { k = key; v = value; } // metodi dell'interfaccia Entry public K getKey() { return k; } public V getValue() { return v; } } ... } Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... /** Crea la coda a priorita` con il comparatore di default. */ public SortedListPriorityQueue () { entries = new NodePositionList<Entry<K,V>>(); c = new DefaultComparator<K>(); } /** Crea la coda a priorita` con un dato comparatore. */ public SortedListPriorityQueue (Comparator<K> comp) { entries = new NodePositionList<Entry<K,V>>(); c = comp; } /** Crea la coda a priorita` con un dato comparatore e una data lista. * Si assume che gli elementi della lista siano in ordine non decrescente.*/ public SortedListPriorityQueue (PositionList<Entry<K,V>> list, Comparator<K> comp) { entries = list; c = comp; } ... } Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... /** Setta il comparatore per questa coda a priorita`. * @throws IllegalStateException se la coda a p. non e` vuota */ public void setComparator(Comparator<K> comp) throws IllegalStateException { if(!isEmpty()) throw new IllegalStateException("la coda a priorita` non e` vuota"); c = comp; } public int size () {return entries.size(); } public boolean isEmpty () { return entries.isEmpty(); } ... } Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... /** Determina se una chiave e` valida. */ protected boolean checkKey(K key) throws InvalidKeyException { boolean result; try { // controlla se la chiave può essere confrontata con sé stessa result = (c.compare(key,key)==0); } catch (ClassCastException e) { throw new InvalidKeyException("la chiave non è confrontabile"); } return result; } ... } Strutture Dati ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... protected void insertEntry(Entry<K,V> e) { for (Position<Entry<K,V>> posentry : entries.positions()) if (c.compare(e.getKey(), posentry.element().getKey()) <= 0){ entries.addBefore(posentry, e); return; } entries.addLast(e); } ... } addBefore 13 5 Strutture Dati 5 11 15 21 22 ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... protected void insertEntry(Entry<K,V> e) { for (Position<Entry<K,V>> posentry : entries.positions()) if (c.compare(e.getKey(), posentry.element().getKey()) <= 0){ entries.addBefore(posentry, e); return; } entries.addLast(e); } ... } addLast 28 5 Strutture Dati 5 11 15 21 22 ADT Coda a Priorità Implementazione con lista ordinata public class SortedListPriorityQueue<K,V> implements PriorityQueue<K,V> { ... public Entry<K,V> insert (K k, V v) throws InvalidKeyException { checkKey(k);//metodo ausiliario per verificare che una chiave sia valida Entry<K,V> entry = new MyEntry<K,V>(k, v); insertEntry(entry); // metodo ausiliario per l'inserimento return entry; } ... } Strutture Dati ADT Coda a Priorità Esercizi Completare la classe SortedListPriorityQueue con gli altri metodi: public Entry<K,V> min() throws EmptyPriorityQueueException; public Entry<K,V> removeMin() throws EmptyPriorityQueueException; Scrivere una classe UnsortedListPriorityQueue che implementa la Coda a Priorità con una lista non ordinata Strutture Dati Esercizio 1 Scrivere un metodo static<E> void PriorityQueueSort(PositionList<E> L, Comparator<E> comp) che prendendo in input una lista di nodi L e un comparatore comp, ordini la lista usando una coda a priorità. Strutture Dati Esercizio 2 Scrivere una classe PQStack<E> che implementi l'interfaccia Stack<E> usando una coda a priorità Strutture Dati