I am implementing a min-max heap, a type of double-ended priority queue. You can look here here for more information about min-max heaps.
The code for insertion and delete-min operations are simple and available on the net. But, I am also trying to implement the delete-max operation on a min-max heap.
Initially, I felt that delete-max in min-max heap would be same as delete-max in max-min heap(if we consider the subtree of min-max heap containing the maximum element, it resembles a max-min heap). So, the implementation would be simple and analogous to delete-min of min-max heap.
But, there is a problem:
As can be seen in the above figure, though 70 is the max element, the last element(12) of the min-max heap is not in the subtree containing 70. So, can I use it to replace the gap left in left subtree after deletion of 70?
If we don't use that element and instead follow delete-max procedure of max-min heap and use 20 to replace the gap, the next element inserted in the heap will be at right child of 10 and forever there will be no right child of 9.
So, can anyone help me?
I believe that it is correct to remove the rightmost node on the last level and use it to replace the max element that was removed, even if it crosses in the tree. The rationale is the following:
Removing the rightmost node in the last level does not change any of the invariants that need to hold for any nodes within that tree: all of the nodes at min levels are still smaller than all of their descendants, and all of the nodes at max levels are still greater than their descendants.
The tree is still a complete binary tree.
Once you have moved this node over, you can then use the normal fixup procedure in a max-min heap in order to ensure that the left subtree invariants still hold.
Hope this helps!
Related
Let's say we're given with a MAX Heap and we want to delete any of the leaf node, then how much time will it take to delete any of the leaf node and maintain the max heap property?
My main doubt is - will it O(n) time to reach to leaf nodes?
Also, why Binary Heaps has to be a complete Binary Tree and not almost complete Binary tree?
A binary heap is a complete binary tree. All levels are full, except possibly the last, which is left-filled. A binary tree is not necessarily a full binary tree.
In a binary heap of size N, represented in an array, the leaf nodes are in the last half of the array. That is, the nodes from N/2 to N-1 are leaf nodes. Deleting the last node (i.e. a[N-1]) is an O(1) operation: all you have to do is remove the node and decrease the size of the heap.
Removing any other leaf node is potentially an O(log n) operation because you have to:
Move the last node, a[N-1] to the node that you're deleting.
Bubble that item up into the heap, to its proper position.
The first part is, of course, O(1). The second part can require up to log(n) - 1 moves. The average is less than 2, but the worst case is log(n) - 1.
In a MAX heap you can access the leaf node in the heap in O(logn) as it is a complete binary tree and traversing the entire height of the tree takes O(logn)
Once this is done, you can call heapify to build the heap again which takes O(logn)
Almost Complete Binary Tree is no different from Complete Binary Tree except that it has following two restrictions :
At every node after completion of current level only go to next level.
At every node after completion of left node go to right.
Every formula that is applicable to complete binary tree will be applicable to almost complete binary tree.
The only difference is there is a gap at last level from right to left in almost complete binary tree. If there is no gap then it is Complete Binary Tree.
Heap is forced to have this property of being a compete binary tree for effciency purposes
How can I find the smallest leaf node in min Heap using heap operations only?
If it is a binary heap you can take [floor(n/2)]+1 when n is the number of elements on the heap It would give you the left most leaf node.
The only requirement in the min heap is that each node is smaller than its parent. Thus, there is no order between leaves, which means that such leaf can be any node among the second half of the array which is used to store the heap. So, one should traverse n/2 elements (second half of the array) and find the smallest one.
I am trying to implement Dijkstra's algorithm for finding the shortest paths between nodes using Fibonacci Heap with Adjacency List representation for the graph. According to the algorithm I know, we have to find the minimum node in the Heap and then iterate through all its neighbours and update their distances. But to get the current distances of the neighbours(which is stored in each node in the heap), I have to find that particular node from the heap. 'Find' operation takes O(N) time where N is number of nodes in the Fibonacci Heap. So is my algorithm correct or am I missing something? Any help would be greatly appreciated.
An implicit assumption in a Fibonacci heap is that when you enqueue an element into the heap, you can, in time O(1), pull up the resulting node in the Fibonacci heap. There are two common ways you'll see this done.
First, you could use an invasive Fibonacci heap. In this approach, the actual node structures in the graph have extra fields stored in them corresponding to what the Fibonacci heap needs to keep things linked up the right order. If you set things up this way, then when you iterate over a node's neighbors, those neighbors already have the necessary fields built into them, which makes it easy to query the Fibonacci heap on those nodes without needing to do a search for them.
Second, you can have the enqueue operation on the Fibonacci heap return a pointer to the newly-created Fibonacci heap node, then somehow associate each node in the graph with that Fibonacci heap node (maybe store a pointer to it, or have a hash table, etc.). This is the approach I took when I coded up a version of Dijkstra's algorithm that uses Fibonacci heap many years back.
This picture from Wikipedia article has three nodes of a Fibonacci heap marked in blue . What is the purpose of some of the nodes being marked in this data structure ?
Intuitively, the Fibonacci heap maintains a collection of trees of different orders, coalescing them when a delete-min occurs. The hope in constructing a Fibonacci heap is that each tree holds a large number of nodes. The more nodes in each tree, the fewer the number of trees that need to be stored in the tree, and therefore the less time will be spent coalescing trees on each delete-min.
At the same time, the Fibonacci heap tries to make the decrease-key operation as fast as possible. To do this, Fibonacci heaps allow subtrees to be "cut out" of other trees and moved back up to the root. This makes decrease-key faster, but makes each tree hold fewer nodes (and also increases the number of trees). There is therefore a fundamental tension in the structure of the design.
To get this to work, the shape of the trees in the Fibonacci heap have to be somewhat constrained. Intuitively, the trees in a Fibonacci heap are binomial trees that are allowed to lose a small number of children. Specifically, each tree in a Fibonacci heap is allowed to lose at most two children before that tree needs to be "reprocessed" at a later step. The marking step in the Fibonacci heap allows the data structure to count how many children have been lost so far. An unmarked node has lost no children, and a marked node has lost one child. Once a marked node loses another child, it has lost two children and thus needs to be moved back to the root list for reprocessing.
The specifics of why this works are documented in many introductory algorithms textbooks. It's not obvious that this should work at all, and the math is a bit tricky.
Hopefully this provides a useful intuition!
A node is marked when one of its child nodes is cut because of a decrease-key. When a second child is cut, the node also cuts itself from its parent. Marking is done so that you know when the second cut occurs.
Good Explanation from Wiki: Operation decrease key will take the node, decrease the key and if the heap property becomes violated (the new key is smaller than the key of the parent), the node is cut from its parent. If the parent is not a root, it is marked. If it has been marked already, it is cut as well and its parent is marked. We continue upwards until we reach either the root or an unmarked node. Now we set the minimum pointer to the decreased value if it is the new minimum.
After removing the minimum element in a binary heap, i.e. after removing the root, I understand that the heap must be adjusted in order to maintain the heap property.
But the preferred method for doing this appears to be to assign the last leaf to the root and sift it down.
I'm wondering why we don't take the lesser child of what used to be the root and just keep sifting up all the children? Isn't this the same amount of operations, so why is that "assign-the-last-leaf-to-the-root-and-sift-down" method preferred?
Because you have to keep the tree filled from the left hand side on the last row. Sifting up from the top down, you can't guarantee that the last element you sift upwards will be the rightmost element.