Does changing a priority queue element result in resorting the queue? - c++

I have a priority_queue, and I want to modify some of it's contents (the priority value), will the queue be resorted then?
It depends if it resorts on push/pop (more probable, becouse you just need to "insert", not resort whole), or when accessing top or pop.
I really want to change some elements in the queue. Something like that:
priority_queue<int> q;
int a=2,b=3,c=5;
int *ca=&a, *cb=&b, cc=&c;
q.push(a);
q.push(b);
q.push(c); //q is now {2,3,5}
*ca=4;
//what happens to q?
// 1) {3,4,5}
// 2) {4,2,5}
// 3) crash

priority_queue copies the values you push into it. Your assignment at the end there will have zero effect on the order of the priority queue, nor the values stored inside of it.

Unfortunately, the std::priority_queue class doesn't support the increase/decrease_key operations that you're looking for. Of course it's possible to find the element within the heap you want to update, and then call make_heap to restore the binary heap invariants, but this can't be done as efficiently as it should be with the std:: container/algorithms. Scanning the heap to find the item is O(N) and then make_heap is O(N) on top of that - it should be possible to do increase/decrease_key in O(log(N)) for binary heaps that properly support updates.
Boost provides a set of priority queue implementations, which are potentially more efficient than the std::priority_queue (pairing heaps, Fibonacci heaps, etc) and also offer mutability, so you can efficiently perform dynamic updates. So all round, using the boost containers is potentially a much better option.

Okay, after searching a bit I found out how to "resort" queue, so after each priority value change you need to call:
std::make_heap(const_cast<Type**>(&queue.top()),
const_cast<Type**>(&queue.top()) + queue.size(),
ComparerClass());
And queue must be then
std::priority_queue<Type*,vector<Type*>,ComparerClass> queue;
Hope this helps.

I stumbled on this issue while considering the use of priority queues for an A* algorithm.
Basically, C++ priority queues are a very limited toy.
Dynamically changing the priority of a queued element requires to perform a complete reconstruction of the underlying heap manually, which is not even guaranteed to work on a given STL implementation and is grossly inefficient.
Besides, reconstructing the heap requires butt-ugly code, which would have to be hidden in yet another obfuscated class/template.
As for so many other things in C++, you'll have to reinvent the wheel, or find whatever fashionable library that reinvented it for you.

Related

Is the time complexity of push and pop of priority queue and insertion and deletion of max_heap same?

I am confused about time complexity of push pop of priority queue and insertion deletion of max_heap.Do they take same time when the input is very long like 10^5 ??which one will be faster priority queue or max_heap??I am trying to solve a problem where input is very long.But when I use heap I get runtime error.
priority_queue is implemented in terms of a heap, it's just providing the interface that guarantees the heap invariant is maintained (unlike using a plain vector + make_heap, where it's initially a heap, but the developer can break the invariant by misusing the vector directly afterwards).
If you're having troubles with the result of make_heap that you don't have with priority_queue, it's probably because your code for manipulating the heap is incorrect; they should both work equally well (priority_queue just simplifies things for you a bit). Without a reproducer, I can't say what you did wrong.

STL iterable container like priority_queue

I'm new to STL containers (and C++ in general) so thought I would reach out to the community for help. I basically want to have a priority_queue that supports constant iteration. Now, it seems that std::priority_queue doesn't support iteration, so I'm going to have to use something else, but I'm not sure exactly what.
Requirements:
Maintains order on insertion (like a priority queue)
Pop from top of list
Get const access to each element of the list (don't care about the order in the queue for this stage)
One option would be to keep a priority_queue and separately have an unordered_set of references, but I'd rather not have two containers floating around. I could also use a deque and search through for the right insertion position, but I'd rather have the container manage the sorting for me if possible (and constant-time insertion would be nicer than linear-time). Any suggestions?
There are two options that come to mind:
1) Implement your own iterable priority queue, using std::vector and the heap operation algorithms (see Heap Operations here).
2) derive (privately) from priority_queue. This gives you access to the underlying container via data member c. You can then expose iteration, random access, and other methods of interest in your public interface.
Using a std::vector might be enough as others already pointed, but if you want already-ready implementation, maybe use Boost.Heap (which is a library with several priority queue containers): http://www.boost.org/doc/libs/1_53_0/doc/html/heap.html
Boost is a collection of libraries that basically complete the standard library (which is not really big). A lot of C++ developers have boost ready on their dev computer to use it when needed. Just be careful in your choices of libraries.
You can use (ordered) set as a queue. set.begin() will be your top element, and you can pop it via erase(set.begin()).
Have you observed heap (std::make_heap) ? It hasn't order inside of queue, but has priority "pop from top of list" which you need.

Can someone explain the asymptotic complexity of sorted and unsorted priority queues?

For a sorted underlying container, why does it take the priority queue O(nlogn) time to create, yet for an unsorted underlying container it only takes O(n) time to create? Also, why does it take (in the sorted case) O(nlogn) to sort the priority queue?
In either case, are there any helpful diagrams that will help me understand the running times? Is it faster to use a heap in these cases?
A priority queue could be implemented with a max-heap. And in fact, a max heap gives us the asymptotically optimal implementation for a priority queue. So, in the unsorted underlying container case, in order to create a priority queue we are only required to create a heap out of n elements, which can be done with the Heapify algorithm in O(n) time. In the sorted case, we are required to fully sort the elements which is known to be Theta(n) bound.
I think your question can't be answered in general as there is no one and only way to implement a priority queue.
It's rather defined by the operations it is able to perform and there are many ways to implement it, a heap or an AVL tree just beeing some possibilities.
You will have to look up the implementation chosen by the STL implementation you are using to answer this question.
In the documentation of the SGI implementation it reads:
[2] This restriction is the only reason for priority_queue to exist at
all. If iteration through elements is important, you can either use a
vector that is maintained in sorted order, or a set, or a vector that
is maintained as a heap using make_heap, push_heap, and pop_heap.
Priority_queue is, in fact, implemented as a random access container
that is maintained as a heap. The only reason to use the container
adaptor priority_queue, instead of performing the heap operations
manually, is to make it clear that you are never performing any
operations that might violate the heap invariant.
So it just seems to use a heap as you suggested.

Shrinking a std::priority_queue

Given a std::priority_queue to which elements are being added faster than they are being removed by the usual process of repeatedly popping the best element, so that the program is going to run out of memory unless something is done,
Is there any way to throw away the worst half of the elements, while leaving the best half to be processed one at a time as normal?
There isn't a direct way. But a binary heap doesn't really support that operation anyways.
But it's not hard to indirectly do so:
Create a temporary empty priority queue
Swap the main and temporary queues
Enter a loop that pops from the temporary and pushes to the main
Stop when you're happy with the number of copied elements
Destroy the temporary queue.
Clearly not, since the interface to a std::priority_queue is so extremely limited. You could implement your own priority queue that will let you do this using make_heap, push_heap and pop_heap (this is how std::priority_queue is implemented) and implementing your own function to remove the worst half of the elements.
The std::priority_queue is a 2-heap and as such only partially ordered. The data-structure is not useful to locate the best half of the elements differently than extracting them.

Need some advice to choose the proper container

I'm trying to design a task scheduler to a game engine. A task could be an animation, a trigger controller, etc.
My problem is what container to choose. The idea is: when you insert a new task, the container must reorder and put the task in the proper place. Once executed, task could change and be scheduled again or deleted. This is mainly push and pop.
But, if possible, it would be nice if I could have random access to an element, but not vital. No matter if the container supports one or more elements with the same key.
I think that priority queue fits my needs but I saw that is based on vector implementation, and I think that this container must be somehow optimized to push and pop.
Opinions?
(source: adrinael.net)
(original source: Liam Devine)
A priority queue seems to be the best option for you.
As you can see, the pop functions has a constant complexity and the push function is logarithmic in time.
std::vector is pretty good for this task, especially if the "steady-state" size of the container remains reasonably constant (you have a number of tasks on the queue doesn't differ widely).
If you need an updatable queue (and std::priority_queue is not), I would suggest you use the d_ary_heap_indirect (which can be found in the Boost.Graph "detail" folder). This is a priority queue used a lot for Dijkstra and A* algorithms that require an updatable priority queue. Random-access is necessary, anyways. Also, using an indirect makes the insertion and deletion from the queue quite efficient. Finally, you can choose your container (as a template argument), but it has to be random-access (so, you can try either vector or deque). Pop is constant-time, push and/or update is log-time, and the proper choice of container will make the container insertion constant-amortized (and the d_ary_heap_indirect amortizes a second time as well, so I wouldn't worry about that).
The vector is optimized for push and pop at one end. :-)
To prioritize you will have to sort the tasks. A vector isn't that bad, if the number of objects is reasonably small, even if it means copying objects during the sort.
Other containers, like linked lists, instead suffer from the need to allocate a new node for each object.
You can specify the container type you want with std::priority_queue.
However: you're storing pointers (I presume, since it sounds like what you're is
polymorphic and has identity), so copying is cheap. You're managing it
as a heap (that's what std::priority_queue does), so insertions are done
using push_back and a number of swaps (lg(n) max). I can't see any
reason to even consider another structure than std::vector.
std::priority_queue does hide all of the direct access operators (e.g.
operator[]). It does this because if you modify an entry, you're
likely to invalidate the heap (which is a class invariant of the class).
If you do want to provide direct read access, however, the underlying
container is only protected, not private, so you can derive from it
and add the operators you want. I'd very much limit it to const
operators, however.
Depends on how often you're going to be adding tasks and pulling tasks off (and presumably executing them) and how many there are.
If you're going to have tons of little tasks, then prefer priority queue because the cost of node allocation will probably not hurt you as much as the asymptotic growth of n log n for the sort.
If you're going to have a small number of tasks that constantly keep changing priority, then sorting a vector might be reasonable, but you want to use an sorting algorithm that works well when the list is almost sorted.
Scheduling is an art though and you're going to have to profile it once you build it. There's probably too little information at this point so say. I'd lean towards a priority queue, but keep other options in mind if performance isn't adequate.