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

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.

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.

Most efficient way for popping max node from a queue implemented using a linked list? C++

If you have a fifo queue implemented using a linked list, what would be the most efficient way to pop a node with the highest value?
Mergesort would be O(n log n).
Scanning through the list would be O(n).
Can anyone suggest more efficient ways of doing this?
The queue must retain the fifo ordering that operates in the usual manner with enqueue and dequeue, but has an extra method, such as popMax, which pops and returns the node with the highest value.
No code is needed, just some ideas! Thanks!
Is popMax frequent enough that changing it from O(N) to O(logN) justifies extra storage (per node: two pointers plus an index) and extra complexity AND changing enqueue and dequeue from O(1) to O(logN) ??
In the many times I have solved this problem (for different reasons and different employers) the answer to the above has pretty consistently been "Yes". But it might be "no" for you. So first make that decision.
Any improvement on the O(N) needs to be able to remove from the middle of the primary sequence. If the primary sequence would have been a forward only linked list, now it needs links in both directions: One extra pointer.
A heap of pointers, costs another extra pointer (per node, but not in the node). But then dequeue needs to be able to remove from the middle of the heap, which takes an index within the node as a back pointer to its position in the heap.
If it is worth all that, you can easily find (online free) source code for a templated version of a priorityQueue/heap and it should be obvious how to make the heap, objects be node* and the less function given to the heap compare the values inside the nodes pointed to.
Next you change that heap source code (the reason you don't simply use std::priority_queue) such that each time it positions an "object" (meaning a node*) in the queue, it does some kind of callback to notify the object of its new index.
You also need to expose some internals of the heap code. There is a point in any decent version of heap code in which the code deals with a hole (missing element) at index x within the heap, by checking whether the last element of the heap could be correctly moved there (and if so doing that) or if not moving the correct child of the hole into the hole and repeating for the new hole where that child was. Typically that code is not exposed to external callers with x as an input. But it easily can be exposed. Your dequeue function needs that in order to remove from the heap the same element being removed from the list.
For less extra storage, but likely more execution time (though still O(logN) for each function). You could have a heap of nodes instead of a heap of node*. That is the reason in coding this kind of heap, you should code the notify callback generically (similar to less). Then your doubly linked list has indexes instead of pointers (so growth is robust) and the notify function updates the predecessor's forward index and successor's back index. To avoid lots of special casing, you need to have a full circle (maybe including a dummy node) of double links, rather than just end to end.
I haven't worked through the details yet myself (since I've never redone any of this in the post C++11 world) but I think a more elegant alternative to the notify function discussed above would be to wrap the object (that will be in the heap) in a wrapper that allows it to be moved but doesn't allow it to be copied. The action to be done by notify would instead be done during the move. That makes std::priority_queue even closer to what you need, but so far as I understand, it still doesn't expose that key internal point in the code for filling a hole at an arbitrary location.

Which one to use? Vector or List

I have to store 10 elements of type card (user defined class). I cannot decide whether to go with vector or list. Following are the operations I would be performing on the structure:
Appending or Inserting at the end of the structure
(better to go with vector).
Ramdom access(element to be accessed can be at end, begining or any position in the structure) (again vector is a better choice).
To delete the random accessed element i.e. Erasing an element from begining or end or any position
(Vector only good for end positions, elsewhere list preferred).
Move element from one position to other such that the element is not swapped with the element at desired position but it gets
inserted within (List are much better here).
To move more than one elements in the same manner as point 4.
(Again I would prefer list)
So can you please guide me which one to pick.
Thanks a ton!
Sounds like you have done your research on vector and list, as you can see there are some conflicting requirements. One other thing to consider is perhaps the frequent of those operations. I.e how often are you expecting to be inserting or deleting from the middle of the collection. Another consideration is the size of the collection, 10 elements is a very small collection so copying 10 elements around isn't a big deal unless you are doing it very frequently. My default choice would be vector, but you can profile both to see which one performs better.

Priority queue and Prim's Algorithm

I have gone through the C++ reference manual and am still unclear on how to use the priorityqueue data structure in STL.
So, basically I have been trying to implement my own using heaps.
I am doing this for implementing Prim's algorithm.
Vector <int, int> pq;
This is my priority queue. The first field is the node and the second field the weight to the existing tree.
I plan to modify the values of weight in pq every time a new node is added to the tree by updating the weights of its neighbour nodes.
How do I access the individual elements of this vector? I also need to be able to delete elements at will.
Is this a good way to implement a priority queue? what if I want to add another field to the container, namely
Vector<int, int, int> MST
How would I access the third element? I want to store the resulting MST this way such that the first two fields represent the vertices forming the edge, and the third the weight.
It would also help if someone could tell me how to assign elements to this vector using push_back.
Also, would the conventional C++ STL priority queue help in this as I need to update the priority values each time a new element is added to the MST? Would it self-correct itself according to the priority when values are modified?
One other question, these Vectors, when I pass them to a function, and try to make changes, is it a pass by value or pass by reference - Or, are the changes reflected outside the function?
In Prim's algorithm the random access to elements not needed. You just need to skip elements from the queue which connect already connected and pass forward.
So the algorithm looks as follows:
choose a node N
add all edges from N to the PQ
pop a minimal cost edge from PQ
if it connects nodes which are already in the tree, skip it
otherwise add this edge to the tree, call the new node N and go back to point 2.
After adding the node just check if size of the tree is already size of graph - 1. If so then finish.
Note that the only operations on PQ are add_element and pop_minimum - thus std::priority_queue will work.
Firstly, std::vector<int,int> isn't valid - the second type argument is an (optional) allocator, and int is not an allocator. If you're using a different underlying container, please say what it is. I'll assume you want to work with std::vector for now.
Secondly, std::priority_queue doesn't support the operations you want (access and delete arbitrary elements), so you can't use that.
You can use the underlying vector directly, and the heap algorithms (std::make_heap etc.) to sort it:
random access will work (although it's not clear what you expect the index to be once your vector is in heap order)
deleting an arbitrary element will require erasing it from the vector and re-running make_heap, or you can implement your own siftDown
Oh, and you can make some value type to store in your vector, such as
std::vector<std::pair<int,int>>
for your first example, or perhaps more clearly:
struct {
int node;
int weight;
} Node;
// ...
std::vector<Node>

c++ heap with removing any element method

I am trying to implement my own heap with the method removing any number (not only the min or max) but I can't solve one problem. To write that removing function I need the pointers to the elements in my heap (to have O(logn) time of removing given element). But when I have tried do it this way:
vector<int*> ptr(n);
it of course did not work.
Maybe I should insert into my heap another class or structure containing int, but for now I would like to find any solution with int (because I have already implemented it using int)?
When you need to remove (or change the priority of) other objects than the root, a d-heap isn't necessarily the ideal data structure: the nodes keep changing their position and you need to keep track of various moves. It is doable, however. To use a heap like this you would return a handle to the newly inserted object which identifies some sort of node which stays put. Since the d-heap algorithm relies on the tree being a perfectly balanced tree, you effectively need to implement it using an array. Since these two requirements (using an array and having nodes stay put) are mutually exclusive you need to do both and have an index from the nodes into the array (so you can find the position of the object in the array) and a pointer from the array to the node (so you can update the node when the position changes). Almost certainly you don't want to move your nodes a lot, i.e. you rather accept finding the proper direction to move a nodes by searching multiple nodes, i.e. you want to use a d > 2.
There are alternative approach to implement a heap which are inherently nodes based. In particular Fibonacci heaps which yield for certain usage patterns a better amortized complexity than the usual O(ln(n)) complexity. However, they are somewhat harder to implement and the actual efficiency only pays off if you either need to change the priority of a node frequently or you have fairly large data sets.
A heap is a particular sort of data structure; the elements are stored in a binary tree, and there are well-established procedures for adding or removing elements. Many implementations use an array to hold the tree nodes, and removing an element involved moving log(n) elements around. Normally the way the array is used, the children of the node at array location n are stored at locations 2n and 2n+1; element 0 is left empty.
This Wikipedia page does a fine job of explaining the algorithms.