/******************************************************************************* * Copyright (c) 2002 - 2006 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.util.collections; import java.util.NoSuchElementException; /** * Simple Heap data structure. */ public abstract class Heap<T> { /** * @return true iff elt1 is considered < elt2 */ abstract protected boolean compareElements(T elt1, T elt2); private int numberOfElements; private T[] backingStore; /** * @return number of elements in this heap */ public int size() { return numberOfElements; } @SuppressWarnings("unchecked") public Heap(int initialCapacity) { numberOfElements = 0; backingStore = (T[])new Object[initialCapacity]; } /** * @return true iff this heap is non-empty */ final public boolean isEmpty() { return numberOfElements == 0; } public void insert(T elt) { ensureCapacity(numberOfElements + 1); bubbleUp(elt, numberOfElements); numberOfElements++; } /** * @return the first object in the priority queue */ public T take() throws NoSuchElementException { if (numberOfElements == 0) { throw new NoSuchElementException(); } T result = backingStore[0]; removeElement(0); return result; } private static int heapParent(int index) { return (index - 1) / 2; } private static int heapLeftChild(int index) { return index * 2 + 1; } private static int heapRightChild(int index) { return index * 2 + 2; } @SuppressWarnings("unchecked") final private void ensureCapacity(int min) { if (backingStore.length < min) { T newStore[] = (T[])new Object[2 * min]; System.arraycopy(backingStore, 0, newStore, 0, backingStore.length); backingStore = newStore; } } /** * SJF: I know this is horribly uglified ... I've attempted to make things as * easy as possible on the JIT, since this is performance critical. * * @param index */ final private void removeElement(int index) { int ne = numberOfElements; T[] bs = backingStore; while (true) { int leftIndex = heapLeftChild(index); if (leftIndex < ne) { int rightIndex = heapRightChild(index); if (rightIndex < ne) { T leftObject = bs[leftIndex]; T rightObject = bs[rightIndex]; if (compareElements(leftObject, rightObject)) { bs[index] = leftObject; index = leftIndex; } else { bs[index] = rightObject; index = rightIndex; } } else { bs[index] = bs[leftIndex]; index = leftIndex; } // manual tail recursion elimination here } else { numberOfElements--; ne = numberOfElements; if (index != ne) { bubbleUp(bs[ne], index); } return; } } } /** * SJF: I know this is uglified ... I've attempted to make things as easy as * possible on the JIT, since this is performance critical. * * @param elt * @param index */ final private void bubbleUp(T elt, int index) { T[] bs = backingStore; while (true) { if (index == 0) { bs[index] = elt; return; } int hpIndex = heapParent(index); T parent = bs[hpIndex]; if (compareElements(parent, elt)) { bs[index] = elt; return; } else { bs[index] = parent; // manual tail recursion elimination index = hpIndex; } } } @Override public String toString() { StringBuffer s = new StringBuffer(); s.append("["); for (int i = 0; i < size(); i++) { if (backingStore[i] != null) { if (i > 0) s.append(","); s.append(backingStore[i].toString()); } } s.append("]"); return s.toString(); } }