Question

How can you get O(1) amortized complexity in the decrease-key operation on a Fibonacci heap? Just finding the node in the Fibonacci heap that contains the element takes O(n) time using a BFS, which should make it impossible to get O(1) amortized time.

For reference, here's my implementation of BFS to search for the node in question:

   public fHeapNode search(int x){
       Stack<fHeapNode> stack = new Stack<fHeapNode>();
        stack.push(minNode);

        //Breath first searching
        while (!stack.empty()) {
            fHeapNode curr = stack.pop();

            if(curr.data==x) {return curr;}

            else{
                if (curr.child != null) {
                    stack.push(curr.child);
                }
                fHeapNode start = curr;
                curr = curr.right;

                while (curr != start) {

                    if (curr.child != null) {
                        stack.push(curr.child);
                    }
                    if(curr.data==x) {return curr;}
                    curr = curr.right;
                }

            }
        }  


        return null;


   }

And here's my code for decrease-key:

       public void decreaseKey(fHeapNode x, double k)
    {
        if (k > x.key) {
        //throw new IllegalArgumentException("entered value is wrong");
        }
        x.key = k;

        fHeapNode tempParent = x.parent;

        if ((tempParent != null) && (x.key < tempParent.key)) {
            cut(x,tempParent);
            cascadingCut(tempParent);
        }

        if (x.key < minNode.key) {
            minNode = x;
        }
    }
Was it helpful?

Solution

Typically, when implementing a Fibonacci heap, your implementation of enqueue would return a pointer to the newly-inserted node. That way, you can store the pointer for later use. You're absolutely right that you'd have to spend O(n) time searching for the node if you don't have a pointer to it.

As an example, here's my own personal implementation of a Fibonacci heap. The enqueue method is given here:

public Entry<T> enqueue(T value, double priority) {
     // ...
}

Notice how it returns an Entry<T> representing that node. The corresponding implementation of decreaseKey has this interface:

public void decreaseKey(Entry<T> entry, double newPriority) {
     // ...
}

Here, the parameter is the Entry<T> corresponding to the node holding the element whose key should be decreased. It's impossible to call this method without having the Entry<T> that was returned by enqueue because otherwise it would be impossible to implement efficiently.

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top