I am trying to create a priority queue consisting of pairs of int, char that gives me the pair with the greater int, but my code is not working properly. What am I doing wrong?
This is my comparator class:
class Compare
{
public:
bool operator() (pair<int, char>a, pair<int, char>b)
{
return a.first > b.first;
}
};
And this is my priority queue:
priority_queue<pair<int, char>, vector<pair<int, char>>, Compare> party;
But if I execute the code:
party.push(make_pair(2, 'A'));
party.push(make_pair(3, 'B'));
cout<<party.top().first;
It returns 2, instead of 3. How do I fix my implementation of the priority queue?
The same fix that Geordi La Forge would use: reverse the polarity:
bool operator() (const pair<int, char> &a, const pair<int, char> &b) const
{
return a.first < b.first;
}
The comparison function always implements strict weak ordering, a.k.a. the logical < operation. But priority_queue, by definition, gives you the largest value in the priority queue, first:
... provides constant time lookup of the largest (by default) element,
But the comparison function is still strict weak ordering:
A Compare type providing a strict weak ordering.
Slightly counter-intuitive, but after a while, it does make sense...
P.S.: The comparison function should be a const function, and take const parameters, for efficiency, as shown in my example; but that's an additional detail.
Priority queue expects Comparator to implement less - as any other container requiring weak ordering. However, it works by placing the bigger element on top. Since you effectively implemented greater, you reversed the queue, and now the smallest element goes on top.
To fix the problem, change your comparator to return lesser of the two elements.
Related
A std::priority_queue uses a std::vector as the default container (Reference this). For sorting on the basis of the first element in a std::vector<pair<int, int>>, we need to define our own comparison function (Reference this). This is what I understand.
Now, the following code returns the k most frequent elements in a non-empty array, in O(NlogK):
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
if(nums.empty())
return vector<int>();
unordered_map< int, int > hashMap;
for(int i=0; i<nums.size(); i++)
hashMap[nums[i]]++;
priority_queue< pair< int, int >> pq;
vector< int > result;
unordered_map< int, int >::iterator it=hashMap.begin();
for(it=hashMap.begin(); it!=hashMap.end(); it++) {
//the first one is frequency and the second one is the value
pq.push(make_pair(it->second, it->first));
//the peculiar implementation below is because we the code to be O(NlogK)
if(pq.size()>(hashMap.size()-k)) {
result.push_back(pq.top().second);
pq.pop();
}
}
return result;
}
};
This code works correctly and gets accepted by the judge - but how? The std::priority_queue, using a std::vector<pair<int, int>> as its underlying container must contain a custom comparison function so that it sorts correctly. So, how does it work?
Frankly, it works because it is designed to do so.
A few things:
a std::priority_queue employs std::less<T>, where T is the underlying sequence value type, as the default comparator when no override is specified.
std::less<T> invokes operator < against two T arguments, resolving to whatever best-fits and/or is available.
Therefore, if this works as you desired with no special override of the sequence type comparator, it must mean that there exists an operator < for std::pair<int,int> that wire this whole thing together.
And indeed there is. Checking the documentation for std::pair<T1,T2>, you'll find there is an operator < overload that effectively does this:
if (lhs.first < rhs.first)
return true;
else if (!(rhs.first < lhs.first))
return lhs.second < rhs.second
else
return false;
Mind-play examples of how this works are left to the reader to think about.
I have a vector which contains lot of elements of my class X .
I need to find the first occurrence of an element in this vector say S such that S.attrribute1 > someVariable. someVariable will not be fixed . How can I do binary_search for this ? (NOT c++11/c++14) . I can write std::binary_search with search function of greater (which ideally means check of equality) but that would be wrong ? Whats the right strategy for fast searching ?
A binary search can only be done if the vector is in sorted order according to the binary search's predicate, by definition.
So, unless all elements in your vector for which "S.attribute1 > someVariable" are located after all elements that are not, this is going to be a non-starter, right out of the gate.
If all elements in your vector are sorted in some other way, that "some other way" is the only binary search that can be implemented.
Assuming that they are, you must be using a comparator, of some sort, that specifies strict weak ordering on the attribute, in order to come up with your sorted vector in the first place:
class comparator {
public:
bool operator()(const your_class &a, const your_class &b) const
{
return a.attribute1 < b.attribute1;
}
};
The trick is that if you want to search using the attribute value alone, you need to use a comparator that can be used with std::binary_search which is defined as follows:
template< class ForwardIt, class T, class Compare >
bool binary_search( ForwardIt first, ForwardIt last,
const T& value, Compare comp );
For std::binary_search to succeed, the range [first, last) must be
at least partially ordered, i.e. it must satisfy all of the following
requirements:
for all elements, if element < value or comp(element, value) is true
then !(value < element) or !comp(value, element) is also true
So, the only requirement is that comp(value, element) and comp(element, value) needs to work. You can pass the attribute value for T, rather than the entire element in the vector to search for, as long as your comparator can deal with it:
class search_comparator {
public:
bool operator()(const your_class &a, const attribute_type &b) const
{
return a.attribute1 < b;
}
bool operator()(const attribute_type &a, const your_class &b) const
{
return a < b.attribute1;
}
};
Now, you should be able to use search_comparator instead of comparator, and do a binary search by the attribute value.
And, all bets are off, as I said, if the vector is not sorted by the given attribute. In that case, you'll need to use std::sort it explicitly, first, or come up with some custom container that keeps track of the vector elements, in the right order, separately and in addition to the main vector that holds them. Using pointers, perhaps, in which case you should be able to execute a binary search on the pointers themselves, using a similar search comparator, that looks at the pointers, instead.
For std::binary_search to succeed, the range need to be sorted.std::binary_search, std::lower_bound works on sorted containers. So every time you add a new element into your vector you need to keep it sorted.
For this purpose you can use std::lower_bound in your insertion:
class X;
class XCompare
{
public:
bool operator()(const X& first, const X& second) const
{
// your sorting logic
}
};
X value(...);
auto where = std::lower_bound(std::begin(vector), std::end(vector), value, XCompare());
vector.insert(where, value);
And again you can use std::lower_bound to search in your vector:
auto where = std::lower_bound(std::begin(vector), std::end(vector), searching_value, XCompare());
Don't forget to check if std::lower_bound was successful:
bool successed = where != std::end(vector) && !(XCompare()(value, *where));
Or directly use std::binary_search if you only want to know that element is in vector.
I want to find the max element of vector of pairs.
My criteria is: the max element is one with highest second value of the pair.
I did this:
auto max_angle = std::max_element(begin(angles), end(angles),
[](const std::pair<int, int>& left, const std::pair<int, int>& right){
return left.second < right.second;
});
Is it possible to do it without writing a predicate? Is there any easier way for pairs since it is a std struct?
No you can't, because by default std::pairs are compared lexicographically, meaning element-wise left to right. As such, your solution is the simplest solution you can have.
I have a map:
std::map<TyString, int> myMap;
However, in some cases I want to std::map::find an entry by making the comparision TyString == TyStringRef, i.e.
myMap.find(TyStringRef("MyString"));
The reason is that TyString wraps a const char * that it allocates and deallocates by itself.
However, for only finding an entry I don't like to allocate a new string, instead I want to use only the reference (TyStringRef only wraps a const char * without allocating or deallocating memory).
Of course I can just convert the TyStringRef to a TyString, but then I have the memory overhead described above.
Is there an intelligent way to solve this?
Thanks!
Note that std::map::find uses operator< per default, or a user-defined comparison functor. So unless you overload operator< for TyString and TyStringRef, you can't lookup a key in logarithmic time. With operator== being overloaded, you can still lookup in linear time, but not using std::map::find.
For this, you should use a generic algorithm from #include <algorithm>, which is independent from the container classes. It can take any type T and compares it using operator== on the result of operator*() of the iterators you pass in.
std::find(sequence.begin(), sequence.end(), myKey);
However, there is one problem: Since you have a std::map, which uses pairs for the iterators, the key-value-pair will be compared. So you have to use std::find_if, which takes a predicate instead of a value to search for. This predicate should return true for the element you are looking for. You want to have the element (pair) for which first == myKey, so you end up with a code like this:
std::find_if(myMap.begin(), myMap.end(), [](const std::pair<TyString,int> & pair) {
return pair.first == TyStringRef("MyString");
};
This conceptually works, but it won't make use of the binary tree in std::map. So it will take linear time compared to logarithmic time of std::map::find.
There is an alternative, which looks a bit strange in the beginning, but it has the advantage that it will be a logarithmic time lookup. It requires you to overload operator<(TyString,TyStringRef). You can use std::lower_bound to find the first element which is not less (greater or equal) some element with respect to a given comparison function.
std::lower_bound(myMap.begin(), myMap.end(), TyStringRef("MyString"),
[](const std::pair<TyString,int> & entry, const & TyStringRef stringRef) {
return entry.first < stringRef;
}
);
After the "lower bound" was found, you still have to test if the keys compare equal. If they don't, the element was not found. Since it might be possible that all elements compare less with the element you're looking for, so the returned iterator might be the end iterator, which should not be dereferenced. So the full code becomes this, which is analogous to std::map::find and returns the end iterator if the key wasn't found:
template<class Map, class KeyCompareType,
class Iterator = typename Map::const_iterator>
Iterator findInMap(const Map &map, const KeyCompareType &key)
{
typedef typename Map::value_type value_type;
auto predicate = [](const value_type & entry, const KeyCompareType & key) {
return entry.first < key;
};
Iterator it = std::lower_bound(map.begin(), map.end(), key, predicate);
if (it != map.end()) {
if (!(it->first == key))
it = map.end();
}
return it;
}
Live example
You could use STLport, which already does this on its own. Maybe other standardlibrary implementations do the same? Alternatively, you could use std::find(), but that would cost you the logarithmic lookup.
I have to write my own implementation of heap in C++, which stores objects of type:
std::pair<City, int>
where City is a structure to store two integers, which represent city coords and string - city name.
I do know how to do this with plain integers, but using pair of values is a little problematic to me.
I've already started to write my heap class, but, as I said, I don't know how to do this with those pairs.
I want the heap to be sorted by the int value of the pair.
If you know how to do it for ints, you're almost there. Treat the pair objects just as you would treat ints when assigning, but for comparison purposes, use .second instead of the value directly.
You could try to use std::make_heap which will put a sequence of your pairs into a heap order, see this online example. To sort by the int value only, use a C++11 lambda expression that will compare the second element of each pair
Alternatively, given that you cannot use any STL heap-related algorithms, but given any self-made implementation of
template<typename RandomIt>
void my_make_heap(RandomIt first, RandomIt last)
{
/* some algorithm using `a < b` to do comparisons */
}
you can rewrite it as (or add an overload)
template<typename RandomIt, typename Compare>
void my_make_heap(RandomIt first, RandomIt last, Compare, cmp)
{
/* SAME algorithm, but now using `cmp(a, b)` to do comparisons */
}
and then call it as my_make_heap(first, last, int_cmp) where the lambda expression compares pairs like this:
typedef std::pair<City, int> Element;
auto int_cmp = [](Element const& lhs, Element const& rhs) {
return lhs.second < rhs.second;
};
So from what i understand :
Your structure is something like this ,
struct node
{
int X_coord;
int y_coord;
string name;
}
And you need to form the Heap based on "int' value of pair ,call it 'x' .
So your pair is
pair<node n , int x> ;
This , is a very readable code for Heap , implemented in a class.
It can be easily modified to your requirement for pair<> value .
Just use , "heap.second" as your key value .