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).
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.
I want to use priority_queue like this:
priority_queue< pair< int, int> ,int ,cmp >
The comparision should be based on the int value in non-decreasing order.
Example:
((2,5),1),((2,5),2),((2,5),3)
Read the template parameters of std::priority_queue again. The second parameter is the underlying container. You can't use an int.
What you seem to be asking is how to store a pair and an int in a priority queue and sort by the int. Well, you've already figured out how to store a pair of ints. Simply expand that idea and store a pairof a pair and int. That's a naïve solution though. Instead, I recommend using a struct with the pair and the int as members so that you can give them descriptive names. Consider using a struct for the pair of ints too. Then simply use a compare functor which compares the third int only in the order of your choosing ignoring the pair.
priority_queue accepts only "one element" by saying one element I mean only a single element of arbitrary type. For having a pair, and int and another component in the priority queue you need to bring all of them as one meaning you need to be build a struct which will hold them. Then you have to use the bool operator < to tell the compiler how to compare the elements of your type .
bool operator < ( const structName& left, const structName& right)
{
return left.number < right. number;
}
this means that the comparison must be done with the member named number.
I know that if I build a heap using STL, it makes a max_heap. And if I want to make a min_heap, I will have to write my own custom comparator. Now, the following comparator,
struct greater1{
bool operator()(const long& a,const long& b) const{
return a>b;
}
};
int main() {
std::vector<long> humble;
humble.push_back(15);
humble.push_back(15);
humble.push_back(9);
humble.push_back(25);
std::make_heap(humble.begin(), humble.end(), greater1());
while (humble.size()) {
std::pop_heap(humble.begin(),humble.end(),greater1());
long min = humble.back();
humble.pop_back();
std::cout << min << std::endl;
}
return 0;
}
The above code I got from off of the internet. I just have one doubt. How is the comparator actually working. And as far as I understand, shouldn't it be something like, return a < b because we want the minimum element to be in the front and then the bigger element in the heap. Why is it return a > b. Doesn't it mean that, if (a>b), then this will return true and a will be put in the heap before b and therefore a bigger element is put in front of a smaller element?
I think you're reading too much into a connection between the comparator semantics and the heap semantics. Remember, the internal details and structure of containers are deliberately abstracted away from you so, the moment you started trying to rationalise about this in terms of how you think the internal structure of a max_heap should look, you got carried away.
In the standard library, default comparators are always less-than. If the relationship between elements for sorting within the particular container/algorithm is not less-than, the container/algorithm will be clever enough to make that transformation (in this case, on usual implementations, by simply passing the operands in the reverse order, like cmp(b,a)!). But, fundamentally, it will always start with a less-than ordering because that is the consistent convention adopted.
So, to invert the ordering of your container, you would take a less-than comparator and turn it into a greater-than comparator, no matter what the physical layout of the container's implementation may (in your opinion) turn out to be.
Furthermore, as an aside, and to echo the Croissant's comments, I would take longs by value … and, in fact, just use std::greater rather than recreating it.
Standard heap builds in such a way that for every element a and its child b, the comparison cmp(b,a) holds, where cmp is the comparator supplied. Note that the first argument to cmp is the child. (Or, abstracting from the internal representation, the standard way is so that cmp(top, other) is true for the first element top and any other other.)
This is obviously done to make the default comparator ("less") build max-heap.
So you need to provide a comparator which you want to return true when a child is supplied as a first argument. For the min-heap, this will be 'greater'.
I already know priority queues are implemented by default as max_priority queues in C++.
But how to make a min priority queue, rather than storing negetive of each number.
Please help , I am unable to find the syntax , and if able to find any syntax unable to use it and understand it :(.
http://www.cplusplus.com/reference/queue/priority_queue/
Use the constructor that allows you to pass your own compare object.
template < class T, class Container = vector,
class Compare = less > class priority_queue
Compare: Comparison class: A class such that the expression comp(a,b), where comp is an object of this class and a and b are elements of the container, returns true if a is to be placed earlier than b in a strict weak ordering operation. This can either be a class implementing a function call operator or a pointer to a function. This defaults to less, which returns the same as applying the less-than operator (a
In C++, the std::set::insert() only inserts a value if there is not already one with the same 'value'. By the same, does this mean operator== or does it mean one for which operator< is false for either ordering, or does it mean something else?
does it mean one for which operator< is false for either ordering?
Yes, if the set uses the default comparator and compares keys using <. More generally, in an ordered container with comparator Compare, two keys k1 and k2 are regarded as equivalent if !Compare(k1,k2) && !Compare(k2,k1).
Keys are not required to implement operator== or anything else; they are just required to be comparable using the container's comparator to give a strict weak ordering.
std::set has a template argument called `Compare' as in this signature:
template < class Key, class Compare = less<Key>,
class Allocator = allocator<Key> > class set;
Compare is used to determine the ordering between elements. Here, the default less<Key> uses the < operator to compare two keys.
If it helps, you can think of a set as just a std::map with meaningless values, ie a std::set<int> can be thought of as a std::map<int, int> where the values are meaningless.
The only comparison that set is allowed to perform on T is via the functor type it was given to do comparisons as part of the template. Thus, that's how it defines equivalence.
For every value in the set, the comparison must evaluate to true for one of the two ordering between that value and the new one. If it's false both ways for any value, then it won't be stored.