package edu.kit.pse.ws2013.routekit.routecalculation;
import java.util.ArrayList;
import java.util.List;
/**
* The priority queue for {@link ArcFlagsDijkstra} and the precalculation.
*/
public class FibonacciHeap {
private FibonacciHeapEntry min = null;
private int size = 0;
/**
* Check if the heap is empty.
*
* @return true if the heap is empty, otherwise false
*/
public boolean isEmpty() {
return min == null;
}
/**
* Returns the size of the heap.
*
* @return the size
*/
public int getSize() {
return size;
}
/**
* Add an entry to the Heap.
*
* @param value
* the value of the entry
* @param priority
* the priority of the entry
* @return the new entry
*/
public FibonacciHeapEntry add(final int value, final int priority) {
final FibonacciHeapEntry newEntry = new FibonacciHeapEntry(value,
priority);
min = merge(min, newEntry);
size++;
return newEntry;
}
/**
* Removes the minimal element of the Heap.
*
* @return the removed element
*/
public FibonacciHeapEntry deleteMin() {
if (isEmpty()) {
return null;
}
final FibonacciHeapEntry minEntry = min;
if (min.getNext() == min) {
min = null;
} else {
min.getPrev().setNext(min.getNext());
min.getNext().setPrev(min.getPrev());
min = min.getNext();
}
size--;
final FibonacciHeapEntry child = minEntry.getChild();
if (child != null) {
FibonacciHeapEntry currentEntry = child;
do {
currentEntry.setParent(null);
currentEntry = currentEntry.getNext();
} while (currentEntry != child);
}
min = merge(min, minEntry.getChild());
if (min == null) {
// System.out.println("A");
return minEntry;
}
// Consolidate
final List<FibonacciHeapEntry> table = new ArrayList<FibonacciHeapEntry>();
final List<FibonacciHeapEntry> queue = new ArrayList<FibonacciHeapEntry>();
for (FibonacciHeapEntry currentEntry = min; queue.isEmpty()
|| queue.get(0) != currentEntry; currentEntry = currentEntry
.getNext()) {
queue.add(currentEntry);
}
for (FibonacciHeapEntry currentEntry : queue) {
while (true) {
final int currentEntryDegree = currentEntry.getDegree();
while (currentEntryDegree >= table.size()) {
table.add(null);
}
final FibonacciHeapEntry other = table.get(currentEntryDegree);
if (other == null) {
table.set(currentEntryDegree, currentEntry);
break;
}
table.set(currentEntryDegree, null);
FibonacciHeapEntry currentMin;
if (other.getPriority() < currentEntry.getPriority()) {
currentMin = other;
} else {
currentMin = currentEntry;
}
FibonacciHeapEntry currentMax;
if (currentMin == other) {
currentMax = currentEntry;
} else {
currentMax = other;
}
currentMax.getNext().setPrev(currentMax.getPrev());
currentMax.getPrev().setNext(currentMax.getNext());
currentMax.setNext(currentMax);
currentMax.setPrev(currentMax);
currentMin.setChild(merge(currentMin.getChild(), currentMax));
currentMax.setParent(currentMin);
currentMax.setMarked(false);
currentMin.increaseDegree();
currentEntry = currentMin;
}
if (currentEntry.getPriority() <= min.getPriority()) {
min = currentEntry;
}
}
return minEntry;
}
/**
* Decreases the key of an entry.
*
* @param entry
* the entry
* @param newPriority
* the new priority
*/
public void decreaseKey(final FibonacciHeapEntry entry,
final int newPriority) {
// set the new priority
entry.setPriority(newPriority);
// cut the element if the heap property is broken
if (entry.getParent() != null
&& entry.getPriority() <= entry.getParent().getPriority()) {
cut(entry);
}
// the entry has the smalles priority
if (entry.getPriority() <= min.getPriority()) {
min = entry;
}
}
/**
* Merges two heap entries.
*
* @param one
* entry one to merge
* @param two
* entry two to merge
* @return the merged entry
*/
private FibonacciHeapEntry merge(final FibonacciHeapEntry one,
final FibonacciHeapEntry two) {
if (one == null && two == null) {
return null;
} else if (one != null && two == null) {
return one;
} else if (two != null && one == null) {
return two;
} else {
final FibonacciHeapEntry oneNext = one.getNext();
one.setNext(two.getNext());
one.getNext().setPrev(one);
two.setNext(oneNext);
two.getNext().setPrev(two);
if (one.getPriority() < two.getPriority()) {
return one;
} else {
return two;
}
}
}
/**
* Cuts the given entry and recursively repeats it if the parent is marked.
*
* @param entry
* the entry to cut
*/
private void cut(final FibonacciHeapEntry entry) {
entry.setMarked(false);
if (entry.getParent() == null) {
return;
}
if (entry.getNext() != entry) {
entry.getNext().setPrev(entry.getPrev());
entry.getPrev().setNext(entry.getNext());
}
if (entry.getParent().getChild() == entry) {
if (entry.getNext() != entry) {
entry.getParent().setChild(entry.getNext());
} else {
entry.getParent().setChild(null);
}
}
entry.getParent().decreaseDegree();
entry.setPrev(entry);
entry.setNext(entry);
merge(min, entry);
if (entry.getParent().isMarked()) {
cut(entry.getParent());
} else {
entry.getParent().setMarked(true);
}
entry.setParent(null);
}
}