Lets say I have some struct like this:
struct point{
int x, y;
//constructor
};
Then my comparison method:
bool operator < (point a, point b){
if(a.x < b.x) return true;
if(a.x == b.x) return a.y < b.y;
return false;
}
When I create:
priority_queue<point> Q;
It sorts maximum-based (the top element will the one with greatest x, etc).
How can I sort by minimum without change my comparison method? (Obviously I could do something like this:
bool operator < (point a, point b){
bool b;
if(a.x < b.x) b = true;
else if(a.x == b.x) b = a.y < b.y;
else b = false;
return !b;
}
But what I'm looking for is keep the comparison as it is (cos is better for me to understand), and just change the priority_queue constructor, like this:
priority_queue<point, reverse> Q;
How can I achieve this?
First you should make an operator> for your struct, if it makes sense to check if one point is less than another, then it makes sense to check if one is greater than another. You can implement it in terms of operator< by simply reversing the arguments.
bool operator>(point a, point b)
{
return b < a;
}
Once you have that, you can make a reversed priority queue using std::greater, from the <functional> header.
std::priority_queue<point, std::vector<point>, std::greater<point>> Q;
If you require this sort of thing often, it might be worth it to define a template alias:
template<typename T, typename C = std::vector<T>>
using reverse_priority_queue = std::priority_queue<T, C, std::greater<T>>;
reverse_priority_queue<point> Q;
Related
So let's say I'm overwriting the inequality checks of a structure describing a point. I have it set to compare the magnitude by default.
I want to have an option to check each value instead, and I was thinking of ways to do it inline. I could make a function that recasts it as a dummy structure so it has a different type when comparing.
struct vec3 {
double x,y,z;
struct _all {double x,y,z};
friend _all All (vec3 &A) { return *(_all*) &vec3;}
struct _any {double x,y,z};
friend _any Any (vec3 &A) { return *(_any*) &vec3;}
friend bool operator < (vec3 &A, double B) { /* does the magnitude check */ }
friend bool operator < (_all &A, double B) { return A.x<B && A.y < B && A.z<B; }
friend bool operator < (_any &A, double B) { return A.x<B || A.y < B || A.z<B; }
};
This is all so I can write
if (All(PointA) < Limit) {}
I have a feeling this breaks a bunch of coding practices, but I'm having a hard time finding any similar problem. Maybe it's safer to use a constructor instead of type changes? Or would it be clearer if I wrote a function IsAnyLessThan(double A) for my structure instead?
I have a vector of structs. I need to check if the struct is or is not in the vector. The entire struct, not any specific member. It throws me this error upon compile time:
binary '==' : no operator found which takes a left-hand operand of type 'NavigationNode'
(or there is no acceptable conversion)
My struct:
struct NavigationNode{
int x, y; //their x and y position on the grid
float f, g, h;
int parentGCost;
int value;
};
NavigationNode currentNode;
The vector
vector<NavigationNode> openList;
My find:
if (find(closedList.begin(), closedList.end(), currentNode) == closedList.end() )
{
}
You need to overload operator==.
As global function:
bool operator==( const NavigationNode& lhs, const NavigationNode& rhs )
{
// compare lhs and rhs
}
Or as member function:
bool operator==( const NavigationNode& other ) const
{
// compare this & other
}
You will have to write an equality operator for your custom type. Assuming all variables have to be the same for two NavigationNode objects to be the same, it should look something like this:
bool floatEqual(float a, float b)
{
// adapt this comparison to fit your use-case - see the notes below
static const int EPSILON = 0.00001; // arbitrarily chosen - needs to be adapted to the occuring values!
return std::abs(a – b) <= EPSILON;
}
bool operator==(NavigationNode const & a, NavigationNode const & b)
{
return a.x == b.x &&
a.y == b.y &&
floatEqual(a.f, b.f) &&
floatEqual(a.g, b.g) &&
floatEqual(a.h, b.h) &&
a.parentGCost == b.parentGCost &&
a.value == b.value;
}
Even if you could also do it as a member function of NavigationNode, the recommended way is to implement the operator== as a free function (that way, both parameters can take advantage of any possible implicit conversions).
Note on float comparison: Due to how floating point numbers are represented, it is not a trivial task to compare them. Just checking for equality might not give the desired results. See e.g. this question for details:
What is the most effective way for float and double comparison?
You need to overload the comparison operator.
If your intention of "==" is "are each of the values contained in my struct equal to the corresponding members in this other struct" then you can write that.
bool operator==(const NavigationNode& lhs, const NavigationNode& rhs)
{
return /* compare each member in here */
}
I have a struct with members x,y,z and w. How do I sort efficiently
first by x, then by y, by z and finally by w in C++?
If you want to implement a lexicographical ordering, then the simplest way is to use std::tie to implement a less-than or greater-than comparison operator or functor, and then use std::sort on a collection of your structs.
struct Foo
{
T x, y, z, w;
};
....
#include <tuple> // for std::tie
bool operator<(const Foo& lhs, const Foo& rhs)
{
// assumes there is a bool operator< for T
return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w);
}
....
#include <algorithm> // for std::sort
std::vector<Foo> v = ....;
std::sort(v.begin(), v.end());
If there is not a natural ordering for Foo, it might be better to define comparison functors instead of implementing comparison operators. You can then pass these to sort:
bool cmp_1(const Foo& lhs, const Foo& rhs)
{
return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w);
}
std::sort(v.begin(), v.end(), cmp_1);
If you do not have C++11 tuple support, you can implement this using std::tr1::tie (use header <tr1/tuple>) or using boost::tie from the boost.tuple library.
You can turn a struct into a std::tuple using std::tie, and use the lexicographic comparison std::tuple::operator<. Here's an example using a lambda to std::sort
#include <algorithm>
#include <tuple>
#include <vector>
struct S
{
// x, y, z, w can be 4 different types!
int x, y, z, w;
};
std::vector<S> v;
std::sort(std::begin(v), std::end(v), [](S const& L, S const& R) {
return std::tie(L.x, L.y, L.z, L.w) < std::tie(R.x, R.y, R.z, R.w);
});
This example supplies std:sort with a comparison operator on-the-fly. If you always want to use lexicographic comparison, you could write a non-member bool operator<(S const&, S const&) that would automatically be selected by std::sort, or by ordered associative containers like std::set and std::map.
Regarding efficiency, from an online reference:
All comparison operators are short-circuited; they do not access tuple
elements beyond what is necessary to determine the result of the
comparison.
If you have a C++11 environment, prefer std::tie over hand-written solutions given here. They are more error-prone and less readable.
This solution has at most 4 comparisons per element-compare and does not require construction of other objects:
// using function as comp
std::sort (quadrupleVec.begin(), quadrupleVec.end(), [](const Quadruple& a, const Quadruple& b)
{
if (a.x != b.x)
return a.x < b.x;
if (a.y != b.y)
return a.y < b.y;
if (a.z != b.z)
return a.z < b.z;
return a.w < b.w;
});
If you roll your own comparison operator, then you can freely throw objects into std::maps or invoke std::sort. This implementation's designed to be simple so you can easily verify and modify it if needed. By only using operator< to compare x, y, z and w, it minimises the number of operators you may need to implement if those variables are not already comparible (e.g. if they're your own structs rather than ints, double, std::strings etc.).
bool operator<(const Q& lhs, const Q& rhs)
{
if (lhs.x < rhs.x) return true;
if (rhs.x < lhs.x) return false;
if (lhs.y < rhs.y) return true;
if (rhs.y < lhs.y) return false;
if (lhs.z < rhs.z) return true;
if (rhs.z < lhs.z) return false;
if (lhs.w < rhs.w) return true;
return false;
}
Sometimes types will define a comparison function that returns -1, 0 or 1 to indicate less-than, equal or greater-than, both as a way to support the implementation of <, <=, ==, !=, >= and > and also because sometimes doing a < then a != or > would repeat a lot of work (consider comparing long textual strings where only the last character differs). If x, y, z and w happen to be of such types and have a higher-performance compare function, you can possibly improve your overall performance with:
bool operator<(const Q& lhs, const Q& rhs)
{
int c;
return (c = lhs.x.compare(rhs.x) ? c :
(c = lhs.y.compare(rhs.y) ? c :
(c = lhs.z.compare(rhs.z) ? c :
lhs.w < rhs.w;
}
I'm trying to insert into a map, where the key is a class. I've overloaded the operator< function in my class as below:
struct MyType
{
int a, b, c;
bool operator<(const MyType& Rhs) const
{
return (a<Rhs.a) || (b<Rhs.b) || (c<Rhs.c);
}
}
But for certain (unique) keys, values are being overwritten in the map.
What is the preferred operator< method for a multi value key?
I've seen Defining operator< for a struct which uses a tuple, but I'd rather write it long hand if I can.
Do this instead:
return std::tie(a, b, c) < std::tie(Rhs.a, Rhs.b, Rhs.c);
You need to #include <tuple>.
This expression
(a<Rhs.a) || (b<Rhs.b) || (c<Rhs.c)
does not create a strict weak ordering: suppose a > Rhs.a, but b < Rhs.b. Your expression returns true, yet it should be false: b should be used to resolve ties only when as are the same, and then cs should be used only when as and bs are the same.
This leads to the following "staircase" expression:
(a<Rhs.a) ||
(a==Rhs.a && b<Rhs.b) ||
(a==Rhs.a && b==Rhs.b && c<Rhs.c)
This is the long way of writing the expression suggested in Kerrek SB's answer, which I recommend you to use for its far superior readability.
The problem is that if you instance two MyType like say for example M1 = {1, 1, 2} and M2 = {1, 2, 1} you have the unfortunate situation that M1 < M2 and M2 < M1!
In order to fix this you need to assign a b and c some significance/order:
struct MyType
{
int a, b, c;
bool operator<(const MyType& Rhs) const
{
if (a < Rhs.a) return true;
if (a > Rhs.a) return false;
if (b < Rhs.b) return true;
if (b > Rhs.b) return false;
return c < Rhs.c;
}
}
(This is a less optimal way to write the expression in dasblinkenlight's answer but maybe easier to understand).
But once you've understood why this is needed you should switch to a tuple, this really is boilerplate code.
If you need map with key of that type and do not need comparator, you might want to use boost::unordered_map and define hasher for your type using boost::hash_combine
I try to use a std::set in order to have unique elements in my container.
Since I have 3D objects :
Class Object3D{
private:
float x;
float y;
float z;
}
Those objects are equal when (A.x==B.x && A.y==B.y && A.z==B.z).
In std::set implementation a element A==B if (!(A < B) && !(B>A)).
It's impossible for my comparison... I have tried to overload == operator.
I chose set container for comparing values when I call insert(a).
I was doing something like that with std::vector v and his iterator:
if(!(A).inVector()){
v.push_back(A);
}
With
bool inVector(){
for(itr = v.begin();itr != v.end();itr++){
if(this->x==(*itr)->x && this->y==(*itr)->y && this->z==(*itr)->z){
return true;
}
}
return false;
}
Checking it for each object (10000-100000) is expensive in complexity.
Can someone have an idea ?
You need to implement a strict weak ordering < for your class. The easiest way is to use the lexicographic ordering provided by tuple:
#include <tuple>
class Object3D
{
public:
bool operator<(Object3D const & rhs) const
{
return std::tie(x, y, z) < std::tie(rhs.x, rhs.y, rhs.z);
}
// ...
};
#OP: std::set is a unique, ordered container. It requires either an operator< or a comparator passed explicitly, which implements a strict weak ordering.
If you don't want to impose an ordering on your elements, don't use an ordered container. You can use std::unordered_set if you just want to detect uniqueness without imposing an ordering.
You need to provide a comparator. You don't want to implement operator<, and I agree with that decision. You shouldn't provide meaningless functions for your class just to satisfy the constraints of some container. Thankfully, you don't need operator<. But you do need a function that has behavior similar to operator<. It doesn't have to mean that one object is considered less than another. It just needs to provide a strict-weak ordering. You can give it any name you want. For example:
bool Compare_by_x_then_y_then_z(const Object3D& lhs, const Object3D& rhs)
{
if (lhs.getX() != rhs.getX()) return lhs.getX() < rhs.getX();
if (lhs.getY() != rhs.getY()) return lhs.getY() < rhs.getY();
return lhs.getZ() < rhs.getZ();
}
You then provide this function to the constructor of your set:
typedef bool(*compT)(const Object3D&, const Object3D&);
std::set<Object3D,compT> objects(Compare_by_x_then_y_then_z);
You must declare operator<. You can do it like this
bool operator<(const Object3D& a, const Object3D& b)
{
if (a.x < b.x) return true;
if (b.x < a.x) return false;
if (a.y < b.y) return true;
if (b.y < a.y) return false;
if (a.z < b.z) return true;
if (b.z < a.z) return false;
return false;
}
It is arbitrary, but it doesn't really matter. As long as operator< gives a consistent ordering you'll be OK.
You have to provide a comparison operator, because std::set needs it for its implementation.
A simple less-than operator would look like this:
bool Object3D::operator<(const Object3D& other) const {
if(x != other.x) return x < other.x;
if(y != other.y) return y < other.y;
return z < other.z;
}