aggiunte altre implementazione di coda prioritaria basata su heap

This commit is contained in:
Fabio Scotto di Santolo
2018-04-03 12:39:13 +02:00
parent 7a7d4beedb
commit 6dbd000912
3 changed files with 253 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
package it.algoritmi.adt;
public interface AdaptablePriorityQueue<K extends Comparable<K>, V> extends PriorityQueue<K, V> {
public void remove(Entry<K, V> entry) throws IllegalArgumentException;
public void replaceKey(Entry<K, V> entry, K key) throws IllegalArgumentException;
public void replaceValue(Entry<K, V> entry, V value) throws IllegalArgumentException;
}

View File

@@ -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<K extends Comparable<K>, V> extends HeapPriorityQueue<K, V>
implements AdaptablePriorityQueue<K, V> {
// ---------------- class AdaptablePQEntry annidata ----------------
/**
* Estensione della classe PQEntry per aggiungere informazioni sulla posizione.
*/
protected static class AdaptablePQEntry<K extends Comparable<K>, V> extends PQEntry<K, V> {
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<K> comparator) {
super(comparator);
}
/** Determina se una voce è valida, controllando la sua posizione. */
protected AdaptablePQEntry<K, V> validate(Entry<K, V> entry) throws IllegalArgumentException {
if (!(entry instanceof AdaptablePQEntry))
throw new IllegalArgumentException("Invalid entry");
AdaptablePQEntry<K, V> locator = (AdaptablePQEntry<K, V>) 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<K, V>) heap.get(i)).setIndex(i);
((AdaptablePQEntry<K, V>) 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<K, V> insert(K key, V value) throws IllegalArgumentException {
checkKey(key);
Entry<K, V> newest = new AdaptablePQEntry<K, V>(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<K, V> entry) throws IllegalArgumentException {
AdaptablePQEntry<K, V> 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<K, V> entry, K key) throws IllegalArgumentException {
AdaptablePQEntry<K, V> locator = validate(entry);
checkKey(key);
locator.setKey(key);
bubble(locator.getIndex());
}
/** Sostituisce il valore di una voce. */
@Override
public void replaceValue(Entry<K, V> entry, V value) throws IllegalArgumentException {
AdaptablePQEntry<K, V> locator = validate(entry);
locator.setValue(value);
}
}

View File

@@ -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<K extends Comparable<K>, V> extends AbstractPriorityQueue<K, V> {
/** Contenitore principale delle voci della coda prioritaria. */
protected ArrayList<Entry<K, V>> 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<K> 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<K, V>(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<K, V> 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<K, V> insert(K key, V value) throws IllegalArgumentException {
checkKey(key); // metodo ausiliario di verifica (può lanciare eccezione)
Entry<K, V> 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<K, V> min() {
if (heap.isEmpty()) return null;
return heap.get(0);
}
/** Elimina e restituisce una delle voci aventi chiave minima. */
@Override
public Entry<K, V> removeMin() {
if (heap.isEmpty()) return null;
Entry<K, V> 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;
}
}