Data Structure - Pairing Heap (Java)

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net 

package chimomo.learning.java.datastructure;

/**
 * Implements a pairing heap.
 * Supports a decreaseKey operation.
 * Note that all "matching" is based on the compareTo method.
 *
 * @author Created by Chimomo
 */
public class PairingHeap> {
    private PairNode root;
    private int size;

    // The tree array for combine siblings.
    private PairNode[] treeArray = new PairNode[5];

    /**
     * Construct the pairing heap.
     */
    public PairingHeap() {
        root = null;
        size = 0;
    }

    // Test program.
    public static void main(String[] args) throws Exception {
        // Create pairing heap.
        PairingHeap h = new PairingHeap<>();
        int numItems = 10000;
        int i;
        int j;

        // Insert.
        System.out.println("Checking; no bad output is good.");
        for (i = 37; i != 0; i = (i + 37) % numItems) {
            h.insert(i);
        }

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

        ArrayList> p = new ArrayList<>();
        for (i = 0; i < numItems; i++) {
            p.add(null);
        }
        for (i = 0, j = numItems / 2; i < numItems; i++, j = (j + 71) % numItems) {
            p.set(j, h.insert(j + numItems));
        }

        // Decrease key.
        for (i = 0, j = numItems / 2; i < numItems; i++, j = (j + 53) % numItems) {
            h.decreaseKey(p.get(j), p.get(j).getValue() - numItems);
        }
        i = -1;

        // Delete min.
        while (!h.isEmpty()) {
            if (h.deleteMin() != ++i) {
                System.out.println("Oops! " + i + " ");
            }
        }
        System.out.println("Check completed.");
    }

    /**
     * Insert into the priority queue, and return a position that can be used by decreaseKey.
     * Duplicates are allowed.
     *
     * @param x The item to insert.
     * @return The node containing the newly inserted item.
     */
    public Position insert(T x) {
        PairNode newNode = new PairNode<>(x);

        if (root == null) {
            root = newNode;
        } else {
            root = compareAndLink(root, newNode);
        }

        size++;
        return newNode;
    }

    /**
     * Find the smallest item in the priority queue.
     *
     * @return The smallest item.
     * @throws Exception If pairing heap is empty.
     */
    public T findMin() throws Exception {
        if (isEmpty()) {
            throw new Exception("Pairing heap is empty!");
        }
        return root.element;
    }

    /**
     * Remove the smallest item from the priority queue.
     *
     * @return The smallest item.
     * @throws Exception If pairing heap is empty.
     */
    public T deleteMin() throws Exception {
        if (isEmpty()) {
            throw new Exception("Pairing heap is empty!");
        }

        T x = findMin();

        // Null it out in case used in decrease key.
        root.element = null;
        if (root.leftChild == null) {
            root = null;
        } else {
            root = combineSiblings(root.leftChild);
        }
        size--;

        return x;
    }

    /**
     * Change the value of the item stored in the pairing heap.
     *
     * @param position Any position returned by insert.
     * @param newValue The new value, which must be smaller than the currently stored value.
     * @throws IllegalArgumentException If position is null.
     * @throws IllegalArgumentException If new value is larger than old.
     */
    public void decreaseKey(Position position, T newValue) {
        if (position == null) {
            throw new IllegalArgumentException("Null position passed to decrease key.");
        }

        PairNode p = (PairNode) position;
        if (p.element == null) {
            throw new IllegalArgumentException("Position already deleted.");
        }
        if (p.element.compareTo(newValue) < 0) {
            throw new IllegalArgumentException("New value/Old value: " + newValue + "/" + p.element);
        }

        p.element = newValue;
        if (p != root) {
            if (p.nextSibling != null) {
                p.nextSibling.prev = p.prev;
            }

            if (p.prev.leftChild == p) {
                p.prev.leftChild = p.nextSibling;
            } else {
                p.prev.nextSibling = p.nextSibling;
            }

            p.nextSibling = null;
            root = compareAndLink(root, p);
        }
    }

    /**
     * Test if the priority queue is logically empty.
     *
     * @return True if empty, false otherwise.
     */
    public boolean isEmpty() {
        return root == null;
    }

    /**
     * Returns number of items stored in the priority queue.
     *
     * @return The size of the priority queue.
     */
    public int size() {
        return size;
    }

    /**
     * Make the priority queue logically empty.
     */
    public void makeEmpty() {
        root = null;
        size = 0;
    }

    /**
     * Internal method that is the basic operation to maintain order.
     * Links first and second together to satisfy heap order.
     *
     * @param first  The root of tree 1, which may not be null. (first.nextSibling MUST be null on entry)
     * @param second The root of tree 2, which may be null.
     * @return The result of the tree merge.
     */
    private PairNode compareAndLink(PairNode first, PairNode second) {
        if (second == null) {
            return first;
        }

        if (second.element.compareTo(first.element) < 0) {
            // Attach first as leftmost child of second.
            second.prev = first.prev;
            first.prev = second;
            first.nextSibling = second.leftChild;
            if (first.nextSibling != null) {
                first.nextSibling.prev = first;
            }
            second.leftChild = first;
            return second;
        } else {
            // Attach second as leftmost child of first.
            second.prev = first;
            first.nextSibling = second.nextSibling;
            if (first.nextSibling != null) {
                first.nextSibling.prev = first;
            }
            second.nextSibling = first.leftChild;
            if (second.nextSibling != null) {
                second.nextSibling.prev = second;
            }
            first.leftChild = second;
            return first;
        }
    }

    /**
     * Double the array length if full.
     *
     * @param array The array.
     * @param index The array index.
     * @return The doubled array.
     */
    private PairNode[] doubleIfFull(PairNode[] array, int index) {
        if (index == array.length) {
            PairNode[] oldArray = array;
            array = new PairNode[index * 2];
            for (int i = 0; i < index; i++) {
                array[i] = oldArray[i];
            }
        }
        return array;
    }

    /**
     * Internal method that implements two-pass merging.
     *
     * @param firstSibling The root of the conglomerate; assumed not null.
     */
    private PairNode combineSiblings(PairNode firstSibling) {
        if (firstSibling.nextSibling == null) {
            return firstSibling;
        }

        // Store the subtrees in an array.
        int numSiblings = 0;
        for (; firstSibling != null; numSiblings++) {
            treeArray = doubleIfFull(treeArray, numSiblings);
            treeArray[numSiblings] = firstSibling;

            // Break links.
            firstSibling.prev.nextSibling = null;
            firstSibling = firstSibling.nextSibling;
        }
        treeArray = doubleIfFull(treeArray, numSiblings);
        treeArray[numSiblings] = null;

        // Combine subtrees two at a time, going left to right.
        int i = 0;
        for (; i + 1 < numSiblings; i += 2) {
            treeArray[i] = compareAndLink(treeArray[i], treeArray[i + 1]);
        }

        // j has the result of last compareAndLink.
        // If an odd number of trees, get the last one.
        int j = i - 2;
        if (j == numSiblings - 3) {
            treeArray[j] = compareAndLink(treeArray[j], treeArray[j + 2]);
        }

        // Now go right to left, merging last tree with next to last.
        // The result becomes the new last.
        for (; j >= 2; j -= 2) {
            treeArray[j - 2] = compareAndLink(treeArray[j - 2], treeArray[j]);
        }

        return treeArray[0];
    }

    /**
     * The position interface represents a type that can be used for the decrease key operation.
     */
    public interface Position {
        /**
         * Returns the value stored at this position.
         *
         * @return the value stored at this position.
         */
        AnyType getValue();
    }

    /**
     * Pairing heap node class, for use with PairingHeap.
     */
    private static class PairNode implements Position {
        // Friendly data; accessible by other package routines.
        public AnyType element;
        public PairNode leftChild;
        public PairNode nextSibling;
        public PairNode prev;

        /**
         * Construct the PairNode.
         *
         * @param element The value stored in the node.
         */
        public PairNode(AnyType element) {
            this.element = element;
            leftChild = null;
            nextSibling = null;
            prev = null;
        }

        /**
         * Returns the value stored at this position.
         *
         * @return the value stored at this position.
         */
        public AnyType getValue() {
            return element;
        }
    }
}

/*
Output:
Checking; no bad output is good.
Check completed.
*/

 

你可能感兴趣的:(Data,Structure)