Data Structure - Binomial Queue (Java)

版权声明:欢迎转载并请注明出处,谢谢~~ https://blog.csdn.net/chimomo/article/details/85338179
package chimomo.learning.java.datastructure;

/**
 * Implements a binomial queue.
 * Note that all "matching" is based on the compareTo method.
 *
 * @author Created by Chimomo
 */
public final class BinomialQueue<T extends Comparable<? super T>> {
    private static final int DEFAULT_TREES = 1;

    // # items in priority queue.
    private int size;

    // An array of tree roots.
    private BinomialNode<T>[] trees;

    /**
     * Construct the binomial queue.
     */
    public BinomialQueue() {
        trees = new BinomialNode[DEFAULT_TREES];
        makeEmpty();
    }

    /**
     * Construct with a single item.
     */
    public BinomialQueue(T item) {
        size = 1;
        trees = new BinomialNode[1];
        trees[0] = new BinomialNode<>(item, null, null);
    }

    /**
     * Test program.
     *
     * @param args The arguments.
     */
    public static void main(String[] args) throws Exception {
        // Construct binomial queue.
        int numItems = 10000;
        BinomialQueue<Integer> bq1 = new BinomialQueue<>();
        BinomialQueue<Integer> bq2 = new BinomialQueue<>();
        int i;
        System.out.println("Starting check.");

        // Insert.
        for (i = 37; i != 0; i = (i + 37) % numItems) {
            if (i % 2 == 0) {
                bq2.insert(i);
            } else {
                bq1.insert(i);
            }
        }

        // Merge.
        bq1.merge(bq2);

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

    /**
     * Expand trees.
     *
     * @param newNumTrees The new number of trees.
     */
    private void expandTrees(int newNumTrees) {
        BinomialNode<T>[] old = trees;
        int oldNumTrees = trees.length;

        trees = new BinomialNode[newNumTrees];
        for (int i = 0; i < Math.min(oldNumTrees, newNumTrees); i++) {
            trees[i] = old[i];
        }
        for (int i = oldNumTrees; i < newNumTrees; i++) {
            trees[i] = null;
        }
    }

    /**
     * Merge binomial queue into the priority queue.
     * Binomial queue becomes empty.
     * Binomial queue must be different from this.
     *
     * @param binomialQueue The other binomial queue.
     */
    public void merge(BinomialQueue<T> binomialQueue) {
        // Avoid aliasing problems.
        if (this == binomialQueue) {
            return;
        }

        size += binomialQueue.size;
        if (size > capacity()) {
            int newNumTrees = Math.max(trees.length, binomialQueue.trees.length) + 1;
            expandTrees(newNumTrees);
        }

        BinomialNode<T> carry = null;
        for (int i = 0, j = 1; j <= size; i++, j *= 2) {
            BinomialNode<T> t1 = trees[i];
            BinomialNode<T> t2 = i < binomialQueue.trees.length ? binomialQueue.trees[i] : null;

            int whichCase = t1 == null ? 0 : 1;
            whichCase += t2 == null ? 0 : 2;
            whichCase += carry == null ? 0 : 4;

            switch (whichCase) {
                case 0: /* No trees */
                case 1: /* Only this */
                    break;
                case 2: /* Only binomialQueue */
                    trees[i] = t2;
                    binomialQueue.trees[i] = null;
                    break;
                case 4: /* Only carry */
                    trees[i] = carry;
                    carry = null;
                    break;
                case 3: /* This and binomialQueue */
                    carry = combineTrees(t1, t2);
                    trees[i] = binomialQueue.trees[i] = null;
                    break;
                case 5: /* This and carry */
                    carry = combineTrees(t1, carry);
                    trees[i] = null;
                    break;
                case 6: /* BinomialQueue and carry */
                    carry = combineTrees(t2, carry);
                    binomialQueue.trees[i] = null;
                    break;
                case 7: /* All three */
                    trees[i] = carry;
                    carry = combineTrees(t1, t2);
                    binomialQueue.trees[i] = null;
                    break;
            }
        }

        for (int k = 0; k < binomialQueue.trees.length; k++) {
            binomialQueue.trees[k] = null;
        }
        binomialQueue.size = 0;
    }

    /**
     * Return the result of merging equal-sized tree1 and tree2.
     */
    private BinomialNode<T> combineTrees(BinomialNode<T> tree1, BinomialNode<T> tree2) {
        if (tree1.element.compareTo(tree2.element) > 0) {
            return combineTrees(tree2, tree1);
        }
        tree2.nextSibling = tree1.leftChild;
        tree1.leftChild = tree2;
        return tree1;
    }

    /**
     * Insert into the priority queue, maintaining heap order.
     * This implementation is not optimized for O(1) performance.
     *
     * @param x The item to insert.
     */
    public void insert(T x) {
        merge(new BinomialQueue<>(x));
    }

    /**
     * Find the smallest item in the priority queue.
     *
     * @return The smallest item, or throw exception if empty.
     */
    public T findMin() throws Exception {
        if (isEmpty()) {
            throw new Exception("Binomial queue is empty!");
        }

        return trees[findMinIndex()].element;
    }

    /**
     * Find index of tree containing the smallest item in the priority queue.
     * The priority queue must not be empty.
     *
     * @return The index of tree containing the smallest item.
     */
    private int findMinIndex() {
        int i;
        int minIndex;
        for (i = 0; trees[i] == null; i++) {
        }

        for (minIndex = i; i < trees.length; i++) {
            if (trees[i] != null && trees[i].element.compareTo(trees[minIndex].element) < 0) {
                minIndex = i;
            }
        }

        return minIndex;
    }

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

        int minIndex = findMinIndex();
        T minItem = trees[minIndex].element;
        BinomialNode<T> deletedTree = trees[minIndex].leftChild;

        // Construct H''.
        BinomialQueue<T> deletedQueue = new BinomialQueue<>();
        deletedQueue.expandTrees(minIndex);
        deletedQueue.size = (1 << minIndex) - 1;
        for (int j = minIndex - 1; j >= 0; j--) {
            deletedQueue.trees[j] = deletedTree;
            deletedTree = deletedTree.nextSibling;
            deletedQueue.trees[j].nextSibling = null;
        }

        // Construct H'.
        trees[minIndex] = null;
        size -= deletedQueue.size + 1;
        merge(deletedQueue);

        return minItem;
    }

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

    /**
     * Make the priority queue logically empty.
     */
    public void makeEmpty() {
        size = 0;
        for (int i = 0; i < trees.length; i++) {
            trees[i] = null;
        }
    }

    /**
     * Return the capacity.
     */
    private int capacity() {
        return (1 << trees.length) - 1;
    }

    /**
     * Binomial queue node class.
     *
     * @param <AnyType> Any type.
     */
    private static class BinomialNode<AnyType> {
        AnyType element; // The data in the node.
        BinomialNode<AnyType> leftChild; // Left child.
        BinomialNode<AnyType> nextSibling; // Next sibling.

        // Constructors.
        BinomialNode(AnyType element) {
            this(element, null, null);
        }

        BinomialNode(AnyType element, BinomialNode<AnyType> leftChild, BinomialNode<AnyType> nextSibling) {
            this.element = element;
            this.leftChild = leftChild;
            this.nextSibling = nextSibling;
        }
    }
}

/*
Output:
Starting check.
Check done.

*/

猜你喜欢

转载自blog.csdn.net/chimomo/article/details/85338179
今日推荐