diff --git a/src/it/algoritmi/adt/AdaptablePriorityQueue.java b/src/it/algoritmi/adt/AdaptablePriorityQueue.java new file mode 100644 index 0000000..a482158 --- /dev/null +++ b/src/it/algoritmi/adt/AdaptablePriorityQueue.java @@ -0,0 +1,11 @@ +package it.algoritmi.adt; + +public interface AdaptablePriorityQueue, V> extends PriorityQueue { + + public void remove(Entry entry) throws IllegalArgumentException; + + public void replaceKey(Entry entry, K key) throws IllegalArgumentException; + + public void replaceValue(Entry entry, V value) throws IllegalArgumentException; + +} diff --git a/src/it/algoritmi/adt/queue/HeapAdaptablePriorityQueue.java b/src/it/algoritmi/adt/queue/HeapAdaptablePriorityQueue.java new file mode 100644 index 0000000..0ab65bc --- /dev/null +++ b/src/it/algoritmi/adt/queue/HeapAdaptablePriorityQueue.java @@ -0,0 +1,115 @@ +package it.algoritmi.adt.queue; + +import java.util.Comparator; + +import it.algoritmi.adt.AdaptablePriorityQueue; +import it.algoritmi.adt.Entry; + +public class HeapAdaptablePriorityQueue, V> extends HeapPriorityQueue + implements AdaptablePriorityQueue { + + // ---------------- class AdaptablePQEntry annidata ---------------- + /** + * Estensione della classe PQEntry per aggiungere informazioni sulla posizione. + */ + protected static class AdaptablePQEntry, V> extends PQEntry { + + private int index; // indice della voce nell'array che realizza lo heap + + public AdaptablePQEntry(K key, V value, int j) { + super(key, value); + setIndex(j); + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + } + // ---------------- fine della classe AdaptablePQEntry annidata -------- + + /** Crea una coda prioritaria flessibile vuota che usa l'ordine naturale. */ + public HeapAdaptablePriorityQueue() { + super(); + } + + /** + * Crea una coda prioritaria flessibile vuota che usa il comparatore fornito. + */ + public HeapAdaptablePriorityQueue(Comparator comparator) { + super(comparator); + } + + /** Determina se una voce è valida, controllando la sua posizione. */ + protected AdaptablePQEntry validate(Entry entry) throws IllegalArgumentException { + if (!(entry instanceof AdaptablePQEntry)) + throw new IllegalArgumentException("Invalid entry"); + AdaptablePQEntry locator = (AdaptablePQEntry) entry; // cast sicuro + int j = locator.getIndex(); + if (j >= heap.size() || heap.get(j) != locator) + throw new IllegalArgumentException("Invalid entry"); + return locator; + } + + /** Scambia tra loro le voci delle celle i e j dell'array. */ + @Override + protected void swap(int i, int j) { + super.swap(i, j); + ((AdaptablePQEntry) heap.get(i)).setIndex(i); + ((AdaptablePQEntry) heap.get(j)).setIndex(j); + } + + /** Ripristina la priorità di ordinamento spostando la voce j in altro/basso. */ + protected void bubble(int j) { + if (j > 0 && compare(heap.get(j), heap.get(parent(j))) < 0) + upheap(j); + else + downheap(j); // però può darsi che non sia necessario alcuno spostamento + } + + /** Inserisce una coppia chiave-valore e restituisce la voce creata. */ + @Override + public Entry insert(K key, V value) throws IllegalArgumentException { + checkKey(key); + Entry newest = new AdaptablePQEntry(key, value, heap.size()); + heap.add(newest); + upheap(heap.size() - 1); + return newest; + } + + /** Elimina dalla coda prioritaria la voce ricevuta. */ + + @Override + public void remove(Entry entry) throws IllegalArgumentException { + AdaptablePQEntry locator = validate(entry); + int j = locator.getIndex(); + if (j == heap.size() - 1) // la voce si trova nell'ultima posizione + heap.remove(heap.size() - 1); // quindi basta eliminarla + else { + swap(j, heap.size() - 1); + heap.remove(heap.size() - 1); + bubble(j); + } + } + + /** Sostituisce la chiave di una voce. */ + @Override + public void replaceKey(Entry entry, K key) throws IllegalArgumentException { + AdaptablePQEntry locator = validate(entry); + checkKey(key); + locator.setKey(key); + bubble(locator.getIndex()); + } + + /** Sostituisce il valore di una voce. */ + @Override + public void replaceValue(Entry entry, V value) throws IllegalArgumentException { + AdaptablePQEntry locator = validate(entry); + locator.setValue(value); + } + +} diff --git a/src/it/algoritmi/adt/queue/HeapPriorityQueue.java b/src/it/algoritmi/adt/queue/HeapPriorityQueue.java new file mode 100644 index 0000000..6bce602 --- /dev/null +++ b/src/it/algoritmi/adt/queue/HeapPriorityQueue.java @@ -0,0 +1,127 @@ +package it.algoritmi.adt.queue; + +import java.util.ArrayList; +import java.util.Comparator; + +import it.algoritmi.adt.Entry; + +public class HeapPriorityQueue, V> extends AbstractPriorityQueue { + + /** Contenitore principale delle voci della coda prioritaria. */ + protected ArrayList> heap = new ArrayList<>(); + + /** Crea una coda prioritaria vuota che usa l'ordine naturale tra le chiavi. */ + public HeapPriorityQueue() { + super(); + } + + /** Crea una coda prioritaria vuota che usa il comparatore fornito. */ + public HeapPriorityQueue(Comparator comparator) { + this.comparator = comparator; + } + + /** Crea una coda prioritaria contenente le coppie chiave-valore fornite. */ + public HeapPriorityQueue(K[] keys, V[] values) { + super(); + for (int j = 0; j < Math.min(keys.length, values.length); j++) + heap.add(new PQEntry(keys[j], values[j])); + heapify(); + } + + protected int parent(int j) { + return (j - 1) / 2; + } + + protected int left(int j) { + return 2 * j + 1; + } + + protected int right(int j) { + return 2 * j + 2; + } + + protected boolean hasLeft(int j) { + return left(j) < heap.size(); + } + + protected boolean hasRight(int j) { + return right(j) < heap.size(); + } + + /** Effettua la costruzione bottom-up dello heap in un tempo lineare. */ + protected void heapify() { + int startIndex = parent(size() - 1); // inizia dal genitore dell'ultima entità + for (int j = startIndex; j >= 0; j--) + downheap(j); + } + + /** Scambia tra loro nella lista le voci di indice i e j. */ + protected void swap(int i, int j) { + Entry tmp = heap.get(i); + heap.set(i, heap.get(j)); + heap.set(j, tmp); + } + + /** Sposta in alto la voce di indice j, se necessario per l'ordinamento */ + protected void upheap(int j) { + while (j > 0) { + int p = parent(j); + if (compare(heap.get(j), heap.get(p)) >= 0) + break; + swap(j, p); + j = p; + } + } + + /** Sposta in alto la voce di indice j, se necessario per l'ordinamento. */ + protected void downheap(int j) { + while (hasLeft(j)) { // prosegue verso il basso (o fino a break) + int leftIndex = left(j); + int smallChildIndex = leftIndex; // il destro può essere minore + if (hasRight(j)) { + int rightIndex = right(j); + if (compare(heap.get(leftIndex), heap.get(rightIndex)) > 0) + smallChildIndex = rightIndex; // il figlio destro è minore + } + if (compare(heap.get(smallChildIndex), heap.get(j)) >= 0) + break; // ordinamento corretto + swap(j, smallChildIndex); + j = smallChildIndex; // prosegue dalla posizione del figlio prescelto + } + } + + /** Restituisce il numero di voci presenti nella coda prioritaria. */ + @Override + public int size() { + return heap.size(); + } + + /** Inserisce una coppia chiave-valore e restituisce la voce creata. */ + @Override + public Entry insert(K key, V value) throws IllegalArgumentException { + checkKey(key); // metodo ausiliario di verifica (può lanciare eccezione) + Entry newest = new PQEntry<>(key, value); + heap.add(newest); // aggiunge alla fine della lista + upheap(heap.size() - 1); // esegue up-heap per la voce appena aggiunta + return newest; + } + + /** Restituisce una della voci aventi chiave minima (senza rimuoverla). */ + @Override + public Entry min() { + if (heap.isEmpty()) return null; + return heap.get(0); + } + + /** Elimina e restituisce una delle voci aventi chiave minima. */ + @Override + public Entry removeMin() { + if (heap.isEmpty()) return null; + Entry answer = heap.get(0); + swap(0, heap.size() - 1); // sposta l'elemento minimo alla fine + heap.remove(heap.size() - 1); // e lo rimuove dall lista + downheap(0); // quindi sistema la radice con down-heap + return answer; + } + +}