I have a problem with stl priority queue.I want to have the priority queue in the increasing
order,which is decreasing by default.Is there any way to do this in priority queue.
And what is the complexity of building stl priority queue.If i use quick sort in an array which takes O(nlgn) is its complexity is similar to using priority queue???
Plz someone ans.Advanced thanx.
priority_queue has template parameters that specify the container type and the comparison to use for ordering. By default, the comparison is less<T>; to get the opposite ordering, use priority_queue<T, vector<T>, greater<T>>.
Insertion into a priority queue takes logarithmic time, so building a queue of N items has complexity O(N logN), the same as building and sorting a vector. But once it's built, insertion into the priority queue is still logarithmic, while insertion into a sorted vector is linear.
Use the type
priority_queue<T, vector<T>, greater<T> >
Use a different comparator as the 3rd template argument of std::priority_queue.
priority_queue is a container adaptor that works on any sequence you define. The performance of insertion is equal to the std::push_heap operation and takes logarithmic time. So the complexity to sorting after all insertions are done isn't equal. If you insert a fixed amount and work the queue afterwards a vector and a single sort could be more efficient.
You can just push values multiplying them by -1 so it will be stored in reverse order unlike the actual default order...and multiply the value with -1 again while retrieving data to get it in its actual form.
Replace T bellow with variable type. You will get your work done
priority_queue<T, vector<T>, greater<T> > PQ;
As example for int type variable you can write it like this:
priority_queue<int, vector<int>, greater<int> > Q;
You can use comparator class/struct to achieve the same in priority queue.
class CompareHeight
{
public:
bool operator()(int &p1, int &p2)
{
return p1 > p2;
}
};
Now declare the priority queue as
priority_queue<int, vector<int>, CompareHeight> pq;
Related
I am trying to write a custom comparator for the following priority queue:
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
The first int in the pair is the key, and the second int is the count of the key. I want my priority queue to put the pair with the largest count at the top.
The following is my functor that has fulfilled my need:
class cmp{
public:
bool operator()(const pair<int,int> a, const pair<int,int> b)const{
return a.second < b.second;
}
};
I do not quite understand why this is the correct way to do it.
Why the comparator returns a.second < b.second instead of a.second > b.second, since I want to put the pair with the most count at top?
And how the priority queue will actually utilize this comparator?
From std::priority_queue's documentation:
Note that the Compare parameter is defined such that it returns true if its first argument comes before its second argument in a weak ordering. But because the priority queue outputs largest elements first, the elements that "come before" are actually output last.
The same happens with std::make_heap(): providing a comparator that returns a < b – what std::less does – results in this function template building a max-heap, i.e., the element with the highest key is at the top of the heap. If you want to build a min-heap, you have to pass operator> instead of operator< or still, use operator< but flip the operands.
To conclude, both std::priority_queue and the function templates for dealing with binary heaps sort their elements so that the top corresponds to the element with the highest key. How two keys compare to each other is, however, up to you. You can control this by providing a custom comparator.
Priority queue syntax in C++:
priority_queue <Type, vector<Type>, ComparisonType > min_heap;
If I want to declare a max heap, I use std::less, otherwise std::greater (min heap). I don't quite get why std::less leads to a max heap, and std::greater min heap?
A quote from cppreference that explains the concept:
Compare - A Compare type providing a strict weak ordering.
Note that the Compare parameter is defined such that it returns true
if its first argument comes before its second argument in a weak
ordering. But because the priority queue outputs largest elements
first, the elements that "come before" are actually output last. That
is, the front of the queue contains the "last" element according to
the weak ordering imposed by Compare.
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > class priority_queue;
I understand the first two template arguments, the first template argument is the data type of the element being stored in the priority queue and the second one is the kind of container that the programmer wants to use, it could be either deque or vector.
But the third argument confuses me a bit, because I have never seen something like it. I'd have done something like:
template <class T, class Container = vector<T>
class priority_queue{
/* Implementation */
};
Does it have something to do with the strict weak ordering criterion necessary for priority queue? If yes, how can I learn more about it? Could you give an example of using the third argument?
I am new to template programming, so I'd really appreciate your help.
The third parameter specifies the comparator class.
The comparator class is responsible for comparing queue elements, in order to determine the queue order. You already understand that the elements in the queue are ordered with the "higher" values first. Well, this is what defines what "higher" means, here.
The comparator class has a simple interface: given two values, return true if the first value is less than the second value, and false otherwise. The default implementation, std::less, uses the traditional < operator to compare the two values.
Use a custom comparator class in order to change the behavior of the priority queue. One example would be to specify std::greater instead of std::less as the comparator class. std::greater uses the > operator, so this creates a priority queue "in opposite order", which gives you the lowest values first, rather than highest one.
Or, you could create your own custom comparator class, such as:
class last_four_bits {
public:
bool operator()(int a, int b) const
{
return (a & 0x0F) < (b & 0x0F);
}
};
This comparator class compares the least four bits of an int only. This, in turn, makes this:
std::priority_queue<int, std::vector<int>, last_four_bits>
look at the least four bits of each int value in the queue, thus ordering all ints with the highest values in the last four bits before the ones with the lesser values, ignoring all other bits in the int.
P.S. Comparator classes are also used with associative containers, sets and maps, and serve the same function there. By carefully crafting a comparator class you can create sets and maps whose iterators iterate over the keys in the set/map in some order other than the lowest to the highest keys (as you understand "lowest" and "highest" to mean, intrinsically).
Please consider following code,
using namespace std;
std::priority_queue<int,vector<int>,std::greater<int>> queue; //first
queue.push(26);
queue.push(12);
queue.push(22);
queue.push(25);
std::cout<<queue.top()<<endl;
std::priority_queue<int,vector<int>,std::less<int>> queue2; //second
queue2.push(26);
queue2.push(12);
queue2.push(22);
queue2.push(25);
std::cout<<queue2.top()<<endl;
Output:
12
26
In first definition I used greater<int> still I am getting 12 (min value) as output, while when I use less<int> I get 26 (max value).
Shouldn't greater<int> create max heap?
As far as the internal algorithm itself is concerned, std::priority_queue always creates "max heap". You just need to teach it to compare the elements in order for it know what's "max".
To determine the ordering for that "max heap", it uses a "less"-style comparison predicate: when given a pair (a, b) (in that specific order) the predicate should tell whether a is less than b. By using the ordering information obtained from the predicate std::priority_queue will make sure that the greater element is at the top of the heap. Standard std::less is an example of such predicate. Whatever predicate you supply, the implementation will treat it as a "less"-style predicate.
If you supply a predicate that implements the opposite comparison (like std::greater), you will naturally end up with minimum element at the top. Basically, one can put it this way: std::priority_queue expects a "less" comparison predicate, and by supplying a "greater" comparison predicate instead you are essentially deceiving the queue (in a well-defined fashion). The primary consequence of that deceit is that for you (the external observer) "max heap" turns into a "min heap".
And this is exactly what you observe.
Because that's their job. less and greater are supposed to model operators < and > respectively and are used by priority_queue to give order to its elements.
They yield opposite results because they're defined to do so (except for equal elements).
Shouldn't greater<int> create max heap?
You're mistaking internal representation of the container with the interface of top() member function, which is supposed to yield the top element, as per the comparator.
std::priority_queue is a "max heap". You provide a less-than operator; and the element at the top is the largest.
In your second example, you provided less-than to be the intuitive std::less; and you see the largest element at the top.
In your first example, you consider a larger int to be "less-than" a smaller int; and the "largest" element based your "less-than" is in fact the smallest int.
Why priority queue have that signature ?
std::priority_queue<int, std::vector<int>, std::greater<int> > third;
For what need std::vector<int>? If I, for example, need to store in queue only ints ?
These are the template arguments for priority_queue. The second one is the backing container used for storing the values and in this case you use vector (which is the default container). In the example above it is passed so that you can change the default comparison predicate with std::greater(i.e. have a priority_queue where the smallest value is at the top). Have a look at the class declaration here.