编程语言
首页 > 编程语言> > 编写一个配对堆(含比较器,Java编程实现)

编写一个配对堆(含比较器,Java编程实现)

作者:互联网

PairingHeap的编程实现

/**
 * Implements a pairing heap.
 * Supports a decreaseKey operation.
 * Note that all "matching" is based on the compareTo method.
 */
public class PairingHeap<T extends Comparable<? super T>> {

    private PairNode<T> root;

    private int theSize;

    /**
     * The Position interface represents a type that can
     * be used for the decreaseKey operation.
     */
    public interface Position<T> {
        /**
         * Returns the value stored at this position.
         * @return the value stored at this position.
         */
        T getValue();
    }
    
    /**
     * Construct the pairing heap.
     */
    public PairingHeap() {
        root = null;
        theSize = 0;
    }

    /**
     * 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<T> insert(T x) {
        PairNode<T> newNode = new PairNode<>(x);
        if(root == null) {
            root = newNode;
        } else {
            root = compareAndLink(root, newNode);
        }
        theSize++;
        return newNode;
    }

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

    /**
     * Remove the smallest item from the priority queue.
     * @return the smallest item.
     * @throws UnderflowException if pairing heap is empty.
     */
    public T deleteMin() {
        if(isEmpty()) {
            throw new UnderflowException();
        }
        T x = findMin();
        root.element = null; // null it out in case used in decreaseKey
        if(root.leftChild == null) {
            root = null;
        } else {
            root = combineSiblings(root.leftChild);
        }
        theSize--;
        return x;
    }

    /**
     * Change the value of the item stored in the pairing heap.
     * @param pos any Position returned by insert.
     * @param newVal the new value, which must be smaller than the currently stored value.
     * @throws IllegalArgumentException if pos is null.
     * @throws IllegalArgumentException if new value is larger than old.
     */
    public void decreaseKey(Position<T> pos, T newVal) {
        if(pos == null) {
            throw new IllegalArgumentException("null Position passed to decreaseKey");
        }
        PairNode<T> p = (PairNode<T>) pos;
        if(p.element == null) {
            throw new IllegalArgumentException("pos already deleted");
        }
        if(p.element.compareTo(newVal) < 0) {
            throw new IllegalArgumentException("newVal/oldval: " + newVal + " /" + p.element);
        }
        p.element = newVal;
        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 size of the priority queue.
     */
    public int size() {
        return theSize;
    }

    /**
     * Make the priority queue logically empty.
     */
    public void makeEmpty() {
        root = null;
        theSize = 0;
    }
    
    /**
     * Private static class for use with PairingHeap.
     */
    private static class PairNode<T> implements Position<T> {
        /**
         * Construct the PairNode.
         * @param theElement the value stored in the node.
         */
        public PairNode(T theElement) {
            element     = theElement;
            leftChild   = null;
            nextSibling = null;
            prev        = null;
        }

        /**
         * Returns the value stored at this position.
         * @return the value stored at this position.
         */
        public T getValue() {
            return element;
        }
        
        // Friendly data; accessible by other package routines
        public T element;
        public PairNode<T>   leftChild;
        public PairNode<T>   nextSibling;
        public PairNode<T>   prev;
    }

    /**
     * Internal method that is the basic operation to maintain order.
     * Links first and second together to satisfy heap order.
     * @param first root of tree 1, which may not be null.
     *    first.nextSibling MUST be null on entry.
     * @param second root of tree 2, which may be null.
     * @return result of the tree merge.
     */
    private PairNode<T> compareAndLink(PairNode<T> first, PairNode<T> 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;
        }
    }

    @SuppressWarnings("unchecked")
    private PairNode<T> [] doubleIfFull(PairNode<T> [] array, int index) {
        if(index == array.length) {
            PairNode<T> [] oldArray = array;
            array = new PairNode[index*2];
            for(int i = 0; i < index; i++) {
                array[i] = oldArray[i];
            }
        }
        return array;
    }
   
    // The tree array for combineSiblings
    @SuppressWarnings("unchecked")
    private PairNode<T> [] treeArray = new PairNode[5];

    /**
     * Internal method that implements two-pass merging.
     * @param firstSibling the root of the conglomerate; assumed not null.
     */
    private PairNode<T> combineSiblings(PairNode<T> 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;
            firstSibling.prev.nextSibling = null;  // break links
            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 (PairNode<T>) treeArray[0];
    }

}

测试

public class PairingHeapTest {
    public static void main(String [] args) {
        PairingHeap<Integer> h = new PairingHeap<>();
        int numItems = 10000;
        int i, j;
        System.out.println("Checking; no bad output is good");
        for(i = 37; i != 0; i = (i+37) % numItems) {
            h.insert(i);
        }
        for(i = 1; i < numItems; i++) {
            if(h.deleteMin() != i) {
                System.out.println("Oops! " + i);
            }
        }
        ArrayList<Position<Integer>> 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));
        }
        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;
        while(!h.isEmpty()) {
            if(h.deleteMin() != ++i) {
                System.out.println("Oops! " + i + " ");
            }
        }
        System.out.println("Check completed");
    }
}

测试结果:

Checking; no bad output is good
Check completed
进阶的JFarmer 发布了565 篇原创文章 · 获赞 1159 · 访问量 36万+ 私信 关注

标签:Java,root,编程,nextSibling,PairNode,return,null,配对,first
来源: https://blog.csdn.net/weixin_43896318/article/details/104463641