/* 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; import java.util.Arrays; public class BinHeap<T> implements OTPPriorityQueue<T> { public static OTPPriorityQueueFactory FACTORY = new BinHeapFactory(); private static final double GROW_FACTOR = 2.0; private double[] prio; private T[] elem; private int size; private int capacity; public BinHeap() { this(1000); } @SuppressWarnings("unchecked") public BinHeap(int capacity) { if (capacity < 10) capacity = 10; this.capacity = capacity; elem = (T[]) new Object[capacity + 1]; // erasure voodoo prio = new double[capacity + 1]; // 1-based indexing size = 0; prio[0] = Double.NEGATIVE_INFINITY; // set sentinel } @Override public int size() { return size; } @Override public boolean empty() { return size <= 0; } @Override public double peek_min_key() { if (size > 0) return prio[1]; else throw new IllegalStateException("An empty queue does not have a minimum key."); } @Override public T peek_min() { if (size > 0) return elem[1]; else return null; } @Override public void insert_or_dec_key(T e, double p) { throw new UnsupportedOperationException("BinHeap has no decrease key operation."); } public void rekey(T e, double p) { // Perform "inefficient" but straightforward linear search // for an element then change its key by sifting up or down int i = 0; for (T t : elem) { if (t == e) break; i++; } if (i > size) { //System.out.printf("did not find element %s\n", e); return; } //System.out.printf("found element %s with key %f at %d\n", e, prio[i], i); if (p > prio[i]) { // sift up (as in extract) while (i*2 <= size) { int child = i * 2; if (child != size && prio[child+1] < prio[child]) child ++; if (p > prio[child]) { elem[i] = elem[child]; prio[i] = prio[child]; i = child; } else break; } elem[i] = e; prio[i] = p; } else { // sift down (as in insert) while (prio[i/2] > p) { elem[i] = elem[i/2]; prio[i] = prio[i/2]; i /= 2; } elem[i] = e; prio[i] = p; } } public void dump() { for (int i=0; i<=capacity; i++) { String topMarker = (i > size) ? "(UNUSED)" : ""; System.out.printf("%d\t%f\t%s\t%s\n", i, prio[i], elem[i], topMarker); } System.out.printf("-----------------------\n"); } public void reset() { // empties the queue in one operation size=0; } @Override public void insert(T e, double p) { int i; size += 1; if (size > capacity) resize((int) (capacity * GROW_FACTOR)); for (i = size; prio[i/2] > p; i /= 2) { elem[i] = elem[i/2]; prio[i] = prio[i/2]; } elem[i] = e; prio[i] = p; } @Override public T extract_min() { int i, child; T minElem = elem[1]; T lastElem = elem[size]; double lastPrio = prio[size]; if (size <= 0) return null; size -= 1; for (i=1; i*2 <= size; i=child) { child = i*2; if (child != size && prio[child+1] < prio[child]) child++; if (lastPrio > prio[child]) { elem[i] = elem[child]; prio[i] = prio[child]; } else break; } elem[i] = lastElem; prio[i] = lastPrio; return minElem; } public void resize(int capacity) { // System.out.println("Growing queue to " + capacity); if (capacity < size) throw new IllegalStateException("BinHeap contains too many elements to fit in new capacity."); this.capacity = capacity; prio = Arrays.copyOf(prio, capacity + 1); elem = Arrays.copyOf(elem, capacity + 1); } private static class BinHeapFactory implements OTPPriorityQueueFactory { @Override public <T> OTPPriorityQueue<T> create(int maxSize) { return new BinHeap<T>(maxSize); } } }