/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package org.opentripplanner.common.pqueue;
/*
* Relatively simple priority queue structure with worse asymptotic complexity
* than a Fibonacci heap, but better running time in most real use cases.
*
* Based on the article:
*
* K. Subramani1 and Kamesh Madduri (2009)
* Two-Level Heaps: A New Priority Queue Structure
* with Applications to the Single Source Shortest Path Problem
*
*/
public class TLHeap<T> implements OTPPriorityQueue<T> {
public static OTPPriorityQueueFactory FACTORY = new TLHeapFactory();
private static final double loge2 = Math.log(2);
private int nSubheaps;
private int subheapSize;
private BinHeap<T>[] subheaps;
private int maxSize;
private int size;
private int curHeap;
// base 2 logarithm
private static double log (double x) { return Math.log(x)/loge2; }
// function for finding optimal number of subheaps, see article
private static double optimize(int n, int m) {
double k = log((m * log(log(n))) / (2*n*Math.log(log(n)))) / log(log(n));
return Math.pow(log(n), k); // optimal number of subheaps
}
@SuppressWarnings("unchecked")
public TLHeap (int capacity) {
nSubheaps = (int) optimize(10, 100);
//System.out.println("TLHeap number of subheaps: " + nSubheaps);
if (capacity < nSubheaps) capacity = nSubheaps;
maxSize = capacity;
size = 0;
subheapSize = (maxSize / nSubheaps) + 1;
subheaps = (BinHeap<T>[]) (new BinHeap[nSubheaps]); // erasure casting voodoo
for (int i=0; i<nSubheaps; i++)
subheaps[i] = new BinHeap<T>(subheapSize);
curHeap = 0;
}
@Override
public T extract_min() {
double bestPrio = Double.POSITIVE_INFINITY;
BinHeap<T> bestHeap = null;
for (int i=0; i<nSubheaps; i++) {
BinHeap<T> h = subheaps[i];
if (!h.empty()) {
double p = h.peek_min_key();
if (p < bestPrio) {
bestPrio = p;
bestHeap = h;
}
}
}
size -= 1;
if (bestHeap == null)
return null;
else
return bestHeap.extract_min();
}
@Override
public void insert(T e, double p) {
while (subheaps[curHeap].size() >= subheapSize) {
curHeap += 1;
if (curHeap >= nSubheaps) curHeap = 0;
}
subheaps[curHeap].insert(e, p);
size += 1;
}
@Override
public void insert_or_dec_key(T e, double p) { insert(e, p); } // broken implementation
@Override
public int size() { return size; }
@Override
public boolean empty() { return size <= 0; }
@Override
public double peek_min_key() {
throw new UnsupportedOperationException();
}
@Override
public T peek_min() {
return null;
}
private static class TLHeapFactory implements OTPPriorityQueueFactory {
@Override
public <T> OTPPriorityQueue<T> create(int maxSize) {
return new TLHeap<T>(maxSize);
}
}
}