--- /dev/null
+/*
+ * Copyright (c) 2003, the JUNG Project and the Regents of the University
+ * of California
+ * All rights reserved.
+ *
+ * This software is open-source under the BSD license; see either
+ * "license.txt" or
+ * http://jung.sourceforge.net/license.txt for a description.
+ */
+/*
+ *
+ * Created on Oct 29, 2003
+ */
+package edu.uci.ics.jung.algorithms.util;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Vector;
+
+import org.apache.commons.collections15.IteratorUtils;
+
+/**
+ * An array-based binary heap implementation of a priority queue,
+ * which also provides
+ * efficient <code>update()</code> and <code>contains</code> operations.
+ * It contains extra infrastructure (a hash table) to keep track of the
+ * position of each element in the array; thus, if the key value of an element
+ * changes, it may be "resubmitted" to the heap via <code>update</code>
+ * so that the heap can reposition it efficiently, as necessary.
+ *
+ * @author Joshua O'Madadhain
+ */
+public class MapBinaryHeap<T>
+ extends AbstractCollection<T>
+ implements Queue<T>
+{
+ private Vector<T> heap = new Vector<T>(); // holds the heap as an implicit binary tree
+ private Map<T,Integer> object_indices = new HashMap<T,Integer>(); // maps each object in the heap to its index in the heap
+ private Comparator<T> comp;
+ private final static int TOP = 0; // the index of the top of the heap
+
+ /**
+ * Creates a <code>MapBinaryHeap</code> whose heap ordering
+ * is based on the ordering of the elements specified by <code>c</code>.
+ */
+ public MapBinaryHeap(Comparator<T> comp)
+ {
+ initialize(comp);
+ }
+
+ /**
+ * Creates a <code>MapBinaryHeap</code> whose heap ordering
+ * will be based on the <i>natural ordering</i> of the elements,
+ * which must be <code>Comparable</code>.
+ */
+ public MapBinaryHeap()
+ {
+ initialize(new ComparableComparator());
+ }
+
+ /**
+ * Creates a <code>MapBinaryHeap</code> based on the specified
+ * collection whose heap ordering
+ * will be based on the <i>natural ordering</i> of the elements,
+ * which must be <code>Comparable</code>.
+ */
+ public MapBinaryHeap(Collection<T> c)
+ {
+ this();
+ addAll(c);
+ }
+
+ /**
+ * Creates a <code>MapBinaryHeap</code> based on the specified collection
+ * whose heap ordering
+ * is based on the ordering of the elements specified by <code>c</code>.
+ */
+ public MapBinaryHeap(Collection<T> c, Comparator<T> comp)
+ {
+ this(comp);
+ addAll(c);
+ }
+
+ private void initialize(Comparator<T> comp)
+ {
+ this.comp = comp;
+ clear();
+ }
+
+ /**
+ * @see Collection#clear()
+ */
+ @Override
+ public void clear()
+ {
+ object_indices.clear();
+ heap.clear();
+ }
+
+ /**
+ * Inserts <code>o</code> into this collection.
+ */
+ @Override
+ public boolean add(T o)
+ {
+ int i = heap.size(); // index 1 past the end of the heap
+ heap.setSize(i+1);
+ percolateUp(i, o);
+ return true;
+ }
+
+ /**
+ * Returns <code>true</code> if this collection contains no elements, and
+ * <code>false</code> otherwise.
+ */
+ @Override
+ public boolean isEmpty()
+ {
+ return heap.isEmpty();
+ }
+
+ /**
+ * Returns the element at the top of the heap; does not
+ * alter the heap.
+ */
+ public T peek()
+ {
+ if (heap.size() > 0)
+ return heap.elementAt(TOP);
+ else
+ return null;
+ }
+
+ /**
+ * Removes the element at the top of this heap, and returns it.
+ * @deprecated Use {@link MapBinaryHeap#poll()}
+ * or {@link MapBinaryHeap#remove()} instead.
+ */
+ @Deprecated
+ public T pop() throws NoSuchElementException
+ {
+ return this.remove();
+ }
+
+ /**
+ * Returns the size of this heap.
+ */
+ @Override
+ public int size()
+ {
+ return heap.size();
+ }
+
+ /**
+ * Informs the heap that this object's internal key value has been
+ * updated, and that its place in the heap may need to be shifted
+ * (up or down).
+ * @param o
+ */
+ public void update(T o)
+ {
+ // Since we don't know whether the key value increased or
+ // decreased, we just percolate up followed by percolating down;
+ // one of the two will have no effect.
+
+ int cur = object_indices.get(o).intValue(); // current index
+ int new_idx = percolateUp(cur, o);
+ percolateDown(new_idx);
+ }
+
+ /**
+ * @see Collection#contains(java.lang.Object)
+ */
+ @Override
+ public boolean contains(Object o)
+ {
+ return object_indices.containsKey(o);
+ }
+
+ /**
+ * Moves the element at position <code>cur</code> closer to
+ * the bottom of the heap, or returns if no further motion is
+ * necessary. Calls itself recursively if further motion is
+ * possible.
+ */
+ private void percolateDown(int cur)
+ {
+ int left = lChild(cur);
+ int right = rChild(cur);
+ int smallest;
+
+ if ((left < heap.size()) &&
+ (comp.compare(heap.elementAt(left), heap.elementAt(cur)) < 0)) {
+ smallest = left;
+ } else {
+ smallest = cur;
+ }
+
+ if ((right < heap.size()) &&
+ (comp.compare(heap.elementAt(right), heap.elementAt(smallest)) < 0)) {
+ smallest = right;
+ }
+
+ if (cur != smallest)
+ {
+ swap(cur, smallest);
+ percolateDown(smallest);
+ }
+ }
+
+ /**
+ * Moves the element <code>o</code> at position <code>cur</code>
+ * as high as it can go in the heap. Returns the new position of the
+ * element in the heap.
+ */
+ private int percolateUp(int cur, T o)
+ {
+ int i = cur;
+
+ while ((i > TOP) && (comp.compare(heap.elementAt(parent(i)), o) > 0))
+ {
+ T parentElt = heap.elementAt(parent(i));
+ heap.setElementAt(parentElt, i);
+ object_indices.put(parentElt, new Integer(i)); // reset index to i (new location)
+ i = parent(i);
+ }
+
+ // place object in heap at appropriate place
+ object_indices.put(o, new Integer(i));
+ heap.setElementAt(o, i);
+
+ return i;
+ }
+
+ /**
+ * Returns the index of the left child of the element at
+ * index <code>i</code> of the heap.
+ * @param i
+ * @return the index of the left child of the element at
+ * index <code>i</code> of the heap
+ */
+ private int lChild(int i)
+ {
+ return (i<<1) + 1;
+ }
+
+ /**
+ * Returns the index of the right child of the element at
+ * index <code>i</code> of the heap.
+ * @param i
+ * @return the index of the right child of the element at
+ * index <code>i</code> of the heap
+ */
+ private int rChild(int i)
+ {
+ return (i<<1) + 2;
+ }
+
+ /**
+ * Returns the index of the parent of the element at
+ * index <code>i</code> of the heap.
+ * @param i
+ * @return the index of the parent of the element at index i of the heap
+ */
+ private int parent(int i)
+ {
+ return (i-1)>>1;
+ }
+
+ /**
+ * Swaps the positions of the elements at indices <code>i</code>
+ * and <code>j</code> of the heap.
+ * @param i
+ * @param j
+ */
+ private void swap(int i, int j)
+ {
+ T iElt = heap.elementAt(i);
+ T jElt = heap.elementAt(j);
+
+ heap.setElementAt(jElt, i);
+ object_indices.put(jElt, new Integer(i));
+
+ heap.setElementAt(iElt, j);
+ object_indices.put(iElt, new Integer(j));
+ }
+
+ /**
+ * Comparator used if none is specified in the constructor.
+ * @author Joshua O'Madadhain
+ */
+ private class ComparableComparator implements Comparator<T>
+ {
+ /**
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ @SuppressWarnings("unchecked")
+ public int compare(T arg0, T arg1)
+ {
+ if (!(arg0 instanceof Comparable) || !(arg1 instanceof Comparable))
+ throw new IllegalArgumentException("Arguments must be Comparable");
+
+ return ((Comparable<T>)arg0).compareTo(arg1);
+ }
+ }
+
+ /**
+ * Returns an <code>Iterator</code> that does not support modification
+ * of the heap.
+ */
+ @Override
+ public Iterator<T> iterator()
+ {
+ return IteratorUtils.<T>unmodifiableIterator(heap.iterator());
+ }
+
+ /**
+ * This data structure does not support the removal of arbitrary elements.
+ */
+ @Override
+ public boolean remove(Object o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This data structure does not support the removal of arbitrary elements.
+ */
+ @Override
+ public boolean removeAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This data structure does not support the removal of arbitrary elements.
+ */
+ @Override
+ public boolean retainAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public T element() throws NoSuchElementException
+ {
+ T top = this.peek();
+ if (top == null)
+ throw new NoSuchElementException();
+ return top;
+ }
+
+ public boolean offer(T o)
+ {
+ return add(o);
+ }
+
+ public T poll()
+ {
+ T top = this.peek();
+ if (top != null)
+ {
+ T bottom_elt = heap.lastElement();
+ heap.setElementAt(bottom_elt, TOP);
+ object_indices.put(bottom_elt, new Integer(TOP));
+
+ heap.setSize(heap.size() - 1); // remove the last element
+ if (heap.size() > 1)
+ percolateDown(TOP);
+
+ object_indices.remove(top);
+ }
+ return top;
+ }
+
+ public T remove()
+ {
+ T top = this.poll();
+ if (top == null)
+ throw new NoSuchElementException();
+ return top;
+ }
+
+}