Remove an Element from a heap - heap

My initial approach to implement this method would be to replace the desired element with the last element of the heap and then heapify like you would for removing the root,however this wouldn’t be correct as the last element may not be a child node of the element that is to be removed and the heap structure will be broken.
So how do I go about making sure I am maintaining the heap structure?

replace the desired element with the last element of the heap
Yes, this is the way to go.
and then heapify like you would for removing the root, however this wouldn’t be correct as the last element may not be a child node of the element that is to be removed and the heap structure will be broken.
That concern can be resolved by first checking if the moved value has to bubble up or down, and to apply the appropriate bubble algorithm (up or down).

Related

How do you update values in priority_queue, or is there another way to update keys in heaps in c++

I was going through Djikstra's algorithm when I noticed, I could update keys in heap(with n keys) in O(logn) time (last line in the pseudocode). How do I update keys in heaps in C++, is there any method in priority_queues to do this? Or do I have to write my own heap class to do achieve updates in O(logn) like this?
Edit 1:
Clarifying my need - for a binary heap with n elements -
1) Should insert new values and find & pop minimum values in O(logn)
2) Should update already present keys in O(logn)
I tried to come up with a way to implement this using make_heap, push_heap, pop_heap, and a custom function for update as John Ding suggested.
However I am facing a problem in making the function, I first need to find the location of the key in the heap. Doing this under O(logn) in a heap requires a lookup array for position of keys in heap, see here (I don't know of any other way). However these lookup tables won't be updated when I call push_heap or pop_heap.
You can optimize dijktra algorithm with priority_queue. It is implemented by a binary heap, where you can pop the top or push in a element in O(logN) time. However, due to the encapsulation of priority_queue, you cannot modify the key(more pricisely, decrease the key) of any element.
So our method is to push multiple elements into the heap regardless of whether we have multiple elements refering to the same node.
for example, when
Node N : distance = 30, GraphNode = A(where A refers to one node in the graph, while N is one node in the heap)
is already in the heap, then using the priority_queue cannot help you do such a operation when we try to relax Node N:
decrease_key_to(N, 20)
by decreasing key can make the heap always include less than N elements, but it's cannot be implemented by priority_queue
What we can do with it is to add another node in the heap:
Node N2 : distance = 20, GraphNode = A
push N2 into the heap
That's corresponding to priority_queue::push
So you may need to implement a binary heap supporting decrease_key yourself or find an implementation online, and store a table of pointers pointing to every element in a heap to know access elements through nodes in the graph.
As an extension, using Fibonacci heap can even make decrease_key faster, that's the ultimate level of Dijkstra, Haha :)
Problem of last version of my answer:
We cannot locate the element pushed in to the heap using push_heap.
In order to do this, you need more than the priority_queue provides: you need to know where in the underlying container the element to be updated is stored. In a binary heap, for example, you need to know the position of the element for which you want to change the priority. With this you can change the priority of the element and then restore the heap property in O(log n) by bubbling the modified element up or down.
For Dijkstra, if I remember correctly, something called Fibonacci heap is more efficient than a binary heap.
Unfortunately, std::priority_queue doesn't support updates of entries in the heap, but you may be able to invalidate entries in the heap and wait for them to percolate up to the root from where they can eventually be deleted. So instead of changing an existing entry, you invalidate it and insert another one with the new priority. Whether you can live with the consequences of having invalid entries filling up the heap, is for you to judge.
For an idea how this might work in practice, see here.

What happens when you erase an element from boost::fibonacci_heap?

Does an erase operation also update the heap after the element is removed?
I went through member functions explanation in boost documentation for
fibonacci_heap where it is mentioned what happens after increase/decrease operations, but when it comes to erase the only thing that is stated is that it erases the element pointed by handle.
Does that mean that the heap is reformed after that? If not, what happens to the child nodes of the node that was erased?
Am I missing something obvious?
When erasing an element from a fibonacci heap, the tree is re-consolidated. As a general rule, when the amortized time of an operation on a fibonacci heap is O(log(N)), then tree consolidation is occuring.
Conceptually, a Delete operation can be thought of as being the combination of two operations:
For min-heap implementations, Delete is the combination of Decrease-Key (O(1)) and Extract-Min (O(log(n)).
For max-heap implementations, Delete is the combination of Increase-Key (O(1)) and Extract-Max (O(log(n)).
In practice, the implementation is often optimized to avoid unnecessary steps, but the amortized logarithmic complexity remains the same. In the case of Boost.Heap's fibonacci_heap::erase() the implementation:
cuts off the link between the node and its parent
moves the erase node's children to the root list
consolidates the tree

In c++, how to change the position of elements in a vector and do the same changes to an other different vector?

I have 2 vectors, y and T initially of the same size, and they need to stay separated like this. I do a loop until T is empty and every time it loops, the first element of T is used for an algorithm and then erased from the vector T and pushed into vector S (which is empty at first). Every loop, some values in vector y will change and I need to sort them. My problem is: when I sort y, if y[2] and y[3] swap, I need to swap the elements in T that were at [2] and [3] BEFORE the first loop!
I know this seems weird but this is for a Dijkstra algorithm for my Graph project. I understand if it's not clear and I'll try to clarify if you need it. Any advice will be very helpful for me! Thank you!
If I follow you correctly, T is really a FIFO queue. The first element in it each iteration is being 'popped off the front' and placed elsewhere.
Should you be doing this and want at any time to know an ordering of T which includes the elements that were popped off, perhaps you could not remove them from T at all. Just have an iterator or pointer to the next node to be processed.
That node could either be copied to S, or perhaps S would just contain pointers to the node if it were expensive to copy.
This way you're never actually removing the element from T, simply moving on to look at the next item. Presumably it could be cleaned up at the end.
For the Dijkstra algorithm, you usually use a binary heap to implement a priority queue and visit nodes in ascending order of distance to source nodes. At each visit, neighboring distances may be updated (relax operation) so corresponding queue elements change priority (decrease-key operation).
Instead of using the distance directly as the key of heap elements, use the node identifier (or pointer). But also use a comparison function (as e.g. in std::make_heap and most STL algorithms) that, given two node identifiers, compares the corresponding distances.
This way, node identifiers are re-ordered according to heap operations and, whenever you pop an element from the heap (having minimal distance), you can access any information you like given its node identifier.

What is the best data structure for removing an element from the middle?

The data stucture must be like a stack. Only with one difference. I want to pop from any index not only last. When I have popped element n, the elements with indexes N > n must swap to N-1. Any ideas?
P.S.
Pushing element n into the last index of the stack.
Then popping it out.
Then deleting stack[n]
is a bad idea.
I think you're looking for a linked list.
A linked list (std::list) will allow you to remove an element from the middle with O(1) complexity and automatically "pull" up the elements after it. You can use a linked list like a stack by using push_front. However you need to be aware that accessing an element in a linked list is O(n) as you would need to start at the head of the list and then walk along the links from one element to the next until you have arrived at element n (so there is no O(1) indexing)
Basically you would need to
Create an iterator
advance it to position n
Get the element from the iterator
erase the element the iterator is currently pointing to
Some example code can be found here.
You need to implement a linked list, but unlike an array, the order in a linked list is determined by a pointer in each object. So, you cannot use indices to access the elements.

How does this method of removing an element from a stack work?

I just started taking a C++ class at my local college and the instructor gave the class an assignment in which we must create a vector and remove an element from the middle of the stack.
She provided this example:
vect[3] = vect[vect.size()-1];
vect.pop_back();
Now.. I've tested it and it works I'm just unsure how it works or why it works. I'm sure someone could provide a simple explanation?
You want to delete an element from the middle of the vector, so you simply overwrite it with the last element (with index size()-1) - since the last element thus becomes redundant, we can pop_back() it. Finally we have the desired result - the vector size is decreased by one and the old value at vect[3] is gone.
Note that this doesn't preserve the order of elements in the vector, but it is relatively efficient - erasing from the middle of a vector may involve a lot of memory copying since all elements after the element to be deleted need to be shifted by one to accommodate the gap (remember: a std::vector stores its elements in continuous storage). Erasing from the end costs almost nothing.