簡體   English   中英

斐波那契堆提取最小值實現不起作用

[英]Fibonacci Heap Extract Min Implementation Not Working

我正在實施斐波那契堆以改進我的 Dijkstra 的最短路徑算法。 我的 insert 方法工作正常,接下來我需要做的是 extract-min。 我正在關注 CLRS。 請注意本書中提到的一些屬性還沒有在我的實現中,因為到目前為止這些功能都不需要它們,但我稍后會添加它們。

private static class FibonacciHeap {

    /**
     * Implementation of the node used in
     * fibonacci heap. The nodes are stored
     * as a circular doubly-linked list, making
     * delete and insert operations easy, as
     * well as being able to iterate through
     * without being forced to keep track of the
     * head
     */

    private class Node {

        /**
         * The vertex this node is storing
         */

        Vertex val;

        /**
         * Key used to know the order of vertices
         */

        int key;

        /**
         * The left and right sibling in the list
         */

        Node left, right;

        /**
         * Pointer to one of the child's
         */

        Node child;

        /**
         * The amount of children this node has
         */

        int degree;

        /**
         * Constructs a node with a value and key
         *
         * @param val the value of this node
         * @param key the key of this node
         */

        public Node(Vertex val, int key) {
            this.val = val;
            this.key = key;
        }

        /**
         * Inserts a new node into this node's list.
         * Inserts it to the left of this node, while
         * maintaining the fact that it's circular
         *
         * @param newNode The new node to be inserted
         */

        public void insert(Node newNode) {
            newNode.left = left;
            left.right = newNode;
            newNode.right = this;
            left = newNode;
            if(newNode.key < min.key) {
                min = newNode;
            }

            size++;
        }

        /**
         * Removes this node from it's list
         */

        public void remove() {
            right.left = left;
            left.right = right;
        }

        /**
         * Inserts a new child into this nodes
         * child list
         *
         * @param child The new node to be added as a child
         */

        public void link(Node child) {
            child.remove();

            if(this.child == null) {
                this.child = child;
            } else {
                this.child.insert(child);
            }

            degree ++;
        }

        /**
         * Used for debugging. Will be removed after
         * all operations work fine
         *
         * @return A string representation of this node
         */

        @Override
        public String toString() {
            Node dummy = right;
            StringBuilder sb = new StringBuilder();

            sb.append(key).append(" -> (");
            sb.append(dummy.child);
            sb.append(") ");

            while(dummy != this) {
                sb.append(dummy.key).append(" -> (");
                sb.append(dummy.child);
                sb.append(") ");
                dummy = dummy.right;
            }

            return sb.toString();
        }
    }

    /**
     * Pointer to the node with the smallest key
     */

    private Node min;

    /**
     * Stores the number of nodes in the heap
     */

    private int size;

    /**
     * Creates an empty Fibonacci Heap
     */

    public FibonacciHeap() { }

    /**
     * Gets and returns the key with the
     * smallest value
     *
     * @return the key with the smallest value
     */

    public int getMin() {
        if(min == null) {
            throw new NoSuchElementException("Empty Fibonacci Heap");
        }

        return min.key;
    }

    /**
     * Inserts a vertex along with a key. The
     * key is the one used to measure whether
     * this vertex is lesser than another
     * 
     * @param vertex vertex to be added
     * @param key key of the vertex
     */

    public void insert(Vertex vertex, int key) {
        if(min == null) {
            min = new Node(vertex, key);
            min.left = min;
            min.right = min;
            size = 1;
        } else {
            min.insert(new Node(vertex, key));
        }
    }

    /**
     * Removes the node with the smallest key from
     * the heap, and updates the minimum node if needed
     *
     * @return The node with the smallest key prior to this method call
     */

    public Vertex extractMin() {
        if(isEmpty()) {
            throw new NoSuchElementException("Empty Fibonacci Heap");
        }

        Vertex toReturn;

        if(min == null) {
            toReturn = null;
        } else {
            toReturn = min.val;

            if(min.right == min) {
                min = null;
            } else {
                min.remove();
                min = min.right;
                consolidate();
            }
        }

        return toReturn;
    }

    /**
     * Consolidates the heap. Consolidation is the process
     * making every node in the root list have it's own
     * unique degree. That is, every node in the top most
     * layer has a unique amount of children
     */

    private void consolidate() {
        Node[] degrees = new Node[size];
        degrees[min.degree] = min;
        Node tempMin, dummy = (tempMin = min).right;

        while(dummy != tempMin) {
            if(dummy.key < min.key) {
                min = dummy;
            }

            while(degrees[dummy.degree] != null) {
                Node other = degrees[dummy.degree];

                if(other.key < dummy.key) {
                    Node temp = dummy;
                    dummy = other;
                    other = temp;
                }

                dummy.link(other);
                degrees[dummy.degree - 1] = null;
            }

            degrees[dummy.degree] = dummy;
        }
    }

    /**
     * Returns true if and only if the
     * heap is empty
     *
     * @return if the heap is empty
     */

    public boolean isEmpty() {
        return min == null;
    }

    /**
     * A string representation of this
     * heap. Format of string is:
     * node1 -> (node1.child.toString()) node2 -> (node2.child.toString()) ... noden -> (noden.child.toString())
     * The string representation of the
     * heap is the string representation of
     * the minimum node
     *
     * @return A string representation of this heap
     */

    @Override
    public String toString() {
        return min.toString();
    }

}

這是它提供的堆棧跟蹤:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
    at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.consolidate(DijkstraShortestPath.java:362)
    at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.extractMin(DijkstraShortestPath.java:338)
    at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath.main(DijkstraShortestPath.java:104)

主要錯誤在合並 function 中內部 while 循環的條件語句中給出。 我還在代碼中注釋了這一行。 出了什么問題? 我的主要測試方法是從 1 - 10 中插入 10 個隨機數,然后提取最小值直到它為空。 第一次調用 extract-min 時發生錯誤。

public static void main(String[] args) {
    FibonacciHeap f = new FibonacciHeap();
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < 10; i ++) {
        f.insert(new Vertex(i), (int) (Math.random() * 10));
    }

    while(!f.isEmpty()) {
        System.out.println(f.extractMin());
    }
}

無法確定確切的錯誤。 但是,我可以根據經驗告訴你,在鞏固時你不應該找到最小值。 你鞏固,然后你找到新的最小值。 當您有多個具有相同鍵的節點並且min指向的節點沒有最終出現在根列表中時,您可能會遇到麻煩。

另外,在測試時,不要使用隨機的 function。 創建一個任意數字的數組並將數組中的元素插入到堆中。

我也不明白您的實現如何處理 Fib 堆中只有一個堆有序樹。 那么當你做一個extract-min時會發生什么?

如果需要,可以在此處找到我的 Python 實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM