All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jheaps.array.BinaryArrayIntegerValueHeap Maven / Gradle / Ivy

Go to download

This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and shaded jar.

The newest version!
package org.jheaps.array;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Comparator;
import java.util.NoSuchElementException;

import org.jheaps.Constants;
import org.jheaps.ValueHeap;
import org.jheaps.annotations.ConstantTime;
import org.jheaps.annotations.LogarithmicTime;

/**
 * An optimized array-based binary heap with integer keys.
 *
 * 

* This is a highly optimized implementation which uses (a) the Wegener * bottom-up heuristic and (b) sentinel values. The implementation uses an array * in order to store the elements, providing amortized O(log(n)) time for the * {@code insert} and {@code deleteMin} operations. Operation {@code findMin}, * is a worst-case O(1) operation. All bounds are worst-case if the user * initializes the heap with a capacity larger or equal to the total number of * elements that are going to be inserted into the heap. * *

* See the following papers for details about the optimizations: *

    *
  • Ingo Wegener. BOTTOM-UP-HEAPSORT, a new variant of HEAPSORT beating, on * an average, QUICKSORT (if n is not very small). Theoretical Computer Science, * 118(1), 81--98, 1993.
  • *
  • Peter Sanders. Fast Priority Queues for Cached Memory. Algorithms * Engineering and Experiments (ALENEX), 312--327, 1999.
  • *
* *

* Note that this implementation is not synchronized. If * multiple threads access a heap concurrently, and at least one of the threads * modifies the heap structurally, it must be synchronized externally. * (A structural modification is any operation that adds or deletes one or more * elements or changing the key of some element.) This is typically accomplished * by synchronizing on some object that naturally encapsulates the heap. * * @param * the type of values maintained by this heap * * @author Dimitrios Michail */ public class BinaryArrayIntegerValueHeap implements ValueHeap, Serializable { private static final long serialVersionUID = 1L; /** * Default initial capacity of the heap. */ public static final int DEFAULT_HEAP_CAPACITY = 16; /** * Supremum */ private static final int SUP_KEY = Integer.MAX_VALUE; /** * Infimum */ private static final int INF_KEY = Integer.MIN_VALUE; /** * The maximum heap capacity. */ private static final int MAX_HEAP_CAPACITY = Integer.MAX_VALUE - 8 - 1; /** * The minimum heap capacity. */ private static final int MIN_HEAP_CAPACITY = 0; /** * The array used for representing the heap. */ private Elem[] array; /** * Number of elements in the heap. */ private int size; /** * Minimum capacity due to initially requested capacity. */ private int minCapacity; /** * Constructs a new, empty heap, using the natural ordering of its keys. * *

* The initial capacity of the heap is {@link #DEFAULT_HEAP_CAPACITY} and * adjusts automatically based on the sequence of insertions and deletions. */ public BinaryArrayIntegerValueHeap() { this(DEFAULT_HEAP_CAPACITY); } /** * Constructs a new, empty heap, with a provided initial capacity using the * natural ordering of its keys. * *

* The initial capacity of the heap is provided by the user and is adjusted * automatically based on the sequence of insertions and deletions. The * capacity will never become smaller than the initial requested capacity. * * @param capacity * the initial heap capacity */ @SuppressWarnings("unchecked") public BinaryArrayIntegerValueHeap(int capacity) { checkCapacity(capacity); this.minCapacity = Math.max(capacity, DEFAULT_HEAP_CAPACITY); this.array = (Elem[]) Array.newInstance(Elem.class, minCapacity + 2); this.array[0] = new Elem(INF_KEY, null); for (int i = 1; i < minCapacity + 2; i++) { this.array[i] = new Elem(SUP_KEY, null); } this.size = 0; } /** * {@inheritDoc} */ @Override @ConstantTime public boolean isEmpty() { return size == 0; } /** * {@inheritDoc} */ @Override @ConstantTime public long size() { return size; } /** * {@inheritDoc} */ @Override @ConstantTime public void clear() { size = 0; } /** * {@inheritDoc} */ @Override public Comparator comparator() { return null; } /** * {@inheritDoc} */ @Override @ConstantTime public Integer findMin() { if (Constants.NOT_BENCHMARK && size == 0) { throw new NoSuchElementException(); } return array[1].key; } /** * {@inheritDoc} */ @Override @ConstantTime public V findMinValue() { if (Constants.NOT_BENCHMARK && size == 0) { throw new NoSuchElementException(); } return array[1].value; } /** * {@inheritDoc} */ @Override @LogarithmicTime public void insert(Integer key, V value) { if (Constants.NOT_BENCHMARK) { if (key == null) { throw new NullPointerException("Null keys not permitted"); } // make space if needed if (size == array.length - 2) { if (array.length == 2) { ensureCapacity(1); } else { ensureCapacity(2 * (array.length - 2)); } } } ++size; int hole = size; int pred = hole >> 1; Elem predElem = array[pred]; while (predElem.key > key) { array[hole].key = predElem.key; array[hole].value = predElem.value; hole = pred; pred >>= 1; predElem = array[pred]; } array[hole].key = key; array[hole].value = value; } /** * {@inheritDoc} */ @Override @LogarithmicTime public void insert(Integer key) { insert(key, null); } /** * {@inheritDoc} */ @Override @LogarithmicTime public Integer deleteMin() { if (Constants.NOT_BENCHMARK && size == 0) { throw new NoSuchElementException(); } Integer result = array[1].key; // first move up elements on a min-path int hole = 1; int succ = 2; int sz = size; while (succ < sz) { int key1 = array[succ].key; int key2 = array[succ + 1].key; if (key1 > key2) { succ++; array[hole].key = key2; array[hole].value = array[succ].value; } else { array[hole].key = key1; array[hole].value = array[succ].value; } hole = succ; succ <<= 1; } // bubble up rightmost element int bubble = array[sz].key; int pred = hole >> 1; while (array[pred].key > bubble) { array[hole].key = array[pred].key; array[hole].value = array[pred].value; hole = pred; pred >>= 1; } // finally move data to hole array[hole].key = bubble; array[hole].value = array[sz].value; array[size].key = SUP_KEY; array[size].value = null; size = sz - 1; if (Constants.NOT_BENCHMARK) { // free unused space int currentCapacity = array.length - 2; if (2 * minCapacity <= currentCapacity && 4 * size < currentCapacity) { ensureCapacity(currentCapacity / 2); } } return result; } /** * Ensure that the array representation has the necessary capacity. * * @param capacity * the requested capacity */ @SuppressWarnings("unchecked") private void ensureCapacity(int capacity) { checkCapacity(capacity); Elem[] newArray = (Elem[]) Array.newInstance(Elem.class, capacity + 2); if (newArray.length >= array.length) { System.arraycopy(array, 0, newArray, 0, array.length); for (int i = array.length; i < newArray.length; i++) { newArray[i] = new Elem(SUP_KEY, null); } } else { System.arraycopy(array, 0, newArray, 0, newArray.length); } array = newArray; } /** * Check that a capacity is valid. * * @param capacity * the capacity * * @throws IllegalArgumentException * if the capacity is negative or more than the maximum array * size */ private void checkCapacity(int capacity) { if (capacity < MIN_HEAP_CAPACITY) { throw new IllegalArgumentException("Heap capacity must be >= " + MIN_HEAP_CAPACITY); } if (capacity > MAX_HEAP_CAPACITY) { throw new IllegalArgumentException("Heap capacity too large"); } } private static class Elem implements Serializable { private static final long serialVersionUID = 1L; int key; V value; public Elem(Integer key, V value) { this.key = key; this.value = value; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy