In C++, the standard ordered containers like std::set and std::map use std::less<Key> as the default comparator. However, sometimes we need custom ordering, such as descending order or more complex comparison logic. Here are two common approaches to implement custom comparators.
This approach defines a struct with an overloaded operator() function that performs the comparison.
#include <set>
#include <map>
#include <queue>
struct Descending {
bool operator()(int a, int b) const {
return a > b; // descending order
}
};
// Usage:
set<int, Descending> s; // set using custom comparator
map<int, int, Descending> m; // map using custom comparator
priority_queue<int, vector<int>, Descending> pq; // min-heap: smallest element on topThis modern approach uses a lambda function with decltype to deduce the comparator type.
#include <set>
#include <map>
#include <queue>
// Lambda comparator:
auto cmp = [](int a, int b) {
return a > b; // descending order
};
// Usage:
set<int, decltype(cmp)> s(cmp); // set using lambda comparator
map<int, int, decltype(cmp)> m(cmp); // map using lambda comparator
priority_queue<int, vector<int>, decltype(cmp)> pq(cmp); // min-heap: smallest element on topIn C++, priority_queue uses a comparator that works in reverse logic compared to set/map:
- By default,
priority_queue<int>is a max-heap (largest element on top). - To make a min-heap, use
greater<int>as the comparator. - The comparator returns
trueif the first argument should come after the second in the heap order.
#include <queue>
priority_queue<int> maxHeap; // largest element on top#include <queue>
priority_queue<int, vector<int>, greater<int>> minHeap; // smallest element on topstruct CustomCmp {
bool operator()(int a, int b) const {
return a > b; // min-heap: smaller elements have higher priority
}
};
priority_queue<int, vector<int>, CustomCmp> pq;auto cmp = [](int a, int b) { return a > b; };
priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);Note:
- For
priority_queue, the comparator returnstrueifashould come afterb(i.e., lower priority). - This is the reverse of
set/mapcomparators, wheretruemeans "comes before".
- With the struct approach, you don't need to pass the comparator instance when constructing the container.
- With the lambda approach, you must pass the comparator instance to the container constructor.
- Use
decltype(cmp)to deduce the type of the lambda function. - Both approaches can be extended to work with custom objects by comparing their fields.
- For
priority_queue, remember the comparator logic is reversed compared toset/map.
- Reverse ordering: Sort elements in descending order instead of ascending
- Custom object ordering: Compare objects based on specific fields
- Specialized sorting: Sort strings ignoring case, sort points by distance, etc.
- Priority-based containers: Implement priority queues with custom comparison logic
- For sets/maps of pairs or tuples, remember that only the first component is used in comparison by default
- The comparator must define a strict weak ordering to ensure correct container behavior
- Modifying keys of elements already in a set/map can lead to incorrect ordering
- For
priority_queue, be careful with the reverse logic of the comparator