1. 程式人生 > >Data Structure - Binary Heap (Java)

Data Structure - Binary Heap (Java)

package chimomo.learning.java.datastructure;

/**
 * Implements a binary heap.
 * Note that all "matching" is based on the compareTo method.
 *
 * @author Created by Chimomo
 */
public class BinaryHeap<T extends Comparable<? super T>> {
    private static final int DEFAULT_CAPACITY = 8;

    // The number of elements in heap.
    private int size;

    // The heap array.
    private T[] array;

    /**
     * Construct the binary heap.
     */
    public BinaryHeap() {
        this(DEFAULT_CAPACITY);
    }

    /**
     * Construct the binary heap.
     *
     * @param capacity The capacity of the binary heap.
     */
    public BinaryHeap(int capacity) {
        size = 0;
        array = (T[]) new Comparable[capacity + 1];
    }

    /**
     * Construct the binary heap given an array of items.
     */
    public BinaryHeap(T[] items) {
        size = items.length;
        array = (T[]) new Comparable[(size + 2) * 11 / 10];

        int i = 1;
        for (T item : items) {
            array[i++] = item;
        }
        buildHeap();
    }

    // Test program.
    public static void main(String[] args) throws Exception {
        int numItems = 10000;

        // Construct binary heap.
        BinaryHeap<Integer> binaryHeap = new BinaryHeap<>();

        // Insert.
        for (int i = 37; i != 0; i = (i + 37) % numItems) {
            binaryHeap.insert(i);
        }

        // Find min.
        System.out.println("Min: " + binaryHeap.findMin());

        // Delete min.
        for (int i = 1; i < numItems; i++) {
            if (binaryHeap.deleteMin() != i) {
                System.out.println("Oops! " + i);
            }
        }
    }

    /**
     * Insert into the binary heap, maintaining heap order.
     * Duplicates are allowed.
     *
     * @param x The item to insert.
     */
    public void insert(T x) {
        if (size == array.length - 1) {
            enlargeArray(array.length * 2 + 1);
        }

        // Percolate up.
        int hole = ++size;
        for (array[0] = x; x.compareTo(array[hole >> 1]) < 0; hole /= 2) {
            array[hole] = array[hole >> 1];
        }
        array[hole] = x;
    }

    /**
     * Enlarge array.
     *
     * @param newSize The new size of the array.
     */
    private void enlargeArray(int newSize) {
        T[] old = array;
        array = (T[]) new Comparable[newSize];
        for (int i = 0; i < old.length; i++) {
            array[i] = old[i];
        }
    }

    /**
     * Find the smallest item in the binary heap.
     *
     * @return The smallest item, or throw an Exception if empty.
     */
    public T findMin() throws Exception {
        if (isEmpty()) {
            throw new Exception("Binary heap is empty!");
        }
        return array[1];
    }

    /**
     * Remove the smallest item from the binary heap.
     *
     * @return The smallest item, or throw an exception if empty.
     */
    public T deleteMin() throws Exception {
        if (isEmpty()) {
            throw new Exception("Binary heap is empty!");
        }

        T minItem = findMin();
        array[1] = array[size--];
        percolateDown(1);

        return minItem;
    }

    /**
     * Establish heap order property from an arbitrary arrangement of items.
     * Runs in linear time.
     */
    private void buildHeap() {
        for (int i = size >> 1; i > 0; i--)
            percolateDown(i);
    }

    /**
     * Test if the binary heap is logically empty.
     *
     * @return True if empty, false otherwise.
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Make the binary heap logically empty.
     */
    public void makeEmpty() {
        size = 0;
    }

    /**
     * Internal method to percolate down in the heap.
     *
     * @param hole The index at which the percolate begins.
     */
    private void percolateDown(int hole) {
        int child;
        T tmp = array[hole];

        for (; hole << 1 <= size; hole = child) {
            child = hole << 1;
            if (child != size && array[child + 1].compareTo(array[child]) < 0) {
                child++;
            }
            if (array[child].compareTo(tmp) < 0) {
                array[hole] = array[child];
            } else {
                break;
            }
        }
        array[hole] = tmp;
    }
}

/*
Output:
Min: 1

*/