I have defined a structure Coord as
struct Coord {
int x;
int y;
int z;
};
Overloaded operator!= for Coord
bool Coord::operator !=(Coord& crd)const {
if(this->x != crd.x)
{
if(this->y != crd.y)
{
if(this->z != crd.z)
return true;
else
return false;
}
else
return false;
return true;
}
else
return false;
}
Then initialized a vector variable as
vector<Coord> vcoord;
Now I am using following code to get index of vector having a perticular Coord object
int Index::getVIndex(Coord crd) {
vector<Coord>::iterator it;
int indx;
it = vcoord.begin();
while(it != vcoord.end() && (*it) != crd)
++it;
indx = distance(vcoord.begin(),it);
cerr << (*it).x << " " << (*it).y << " " << indx << endl;
return indx;
}
But the value of indx is always 0. Kindly help to get correct result.
You need a not-equals operator for your Coord struct in order to be able to do this:
(*it) != crd
The logic of your not-equals operator is incorrect. The best and easiest option is to provide an equality comparison and use std::find:
struct Coord {
int x;
int y;
int z;
};
bool operator == (const Coord& lhs, const Coord& rhs)
{
return lhs.x==rhs.x && lhs.y==rhs.y && lhs.z==rhs.z;
}
You can then implement != in terms of ==, but you don't need it if you use std::find, which uses == by default:
vector<Coord>::iterator it = std::find(vcoord.begin(), vcoord.end(), crd);
Your != operator returns true only if all coordinates differ; it should return true if any differ. This means your function will return zero if any coordinate of the first element matches the function argument's.
Your version is a long-winded way of writing:
return x != crd.x && y != crd.y && z != crd.z;
when it should be:
return x != crd.x || y != crd.y || z != crd.z;
It may be easier to get the logic correct by implementing it in terms of ==:
bool operator==(Coord const & lhs, Coord const & rhs) {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
}
bool operator!=(Coord const & lhs, Coord const & rhs) {
return !(lhs == rhs);
}
Also, given a definition of ==, you can use std::find rather than rolling your own loop:
auto found == std::find(vcoord.begin(), vcoord.end(), crd);
if (found == vcoord.end()) {
// Decide what to do if not found.
// Returning zero is a bad idea, since there's no way distinguish that
// from a successful outcome.
} else {
return std::distance(vcoord.begin(), found);
}
You incorrectly implemented the logic in the inequality operator.
It should be
bool Coord::operator !=(const Coord& crd)const {
return x != crd.x || y != crd.y || z != crz.z;
}
Your implementation is logically equivalent to
return x != crd.x && y != crd.y && z != crz.z;
Related
I have the following Edgeclass:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
The point of overriding the < operator is when I try to find an edge in a set Edge(0, 1) should be equal to Edge(1, 0). However, the following test code fails to do so and std::find returns an edge that doesn't even exist:
Edge edge(0, 3);
set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
cout << a->src << " " << a->dest << endl;
This will strangely print out 2 0. I can't figure out why and I'm new to C++ any help is appreciated.
You currently don't have a valid Compare for std::set, so your program has undefined behaviour.
Here is one that is compatible with your ==
bool operator<(const Edge& edge) const {
return std::minmax(src, dest) < std::minmax(edge.src, edge.dest);
}
This can also be used to simplify your ==
bool operator==(const Edge& edge) const {
return std::minmax(src, dest) == std::minmax(edge.src, edge.dest);
}
There are two issues in your code.
First, you do not check whether test.find() returns a valid edge; note that find returns end() if no element was found.
Second, your <-operator does not implement a strict ordering, it actually just defines a !=. To overcome this, I'd normalize each edge such that the lower node is always treated as the start; then decide based on the starting nodes, and only if they are equal, consider the destination nodes:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
// return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
int thisSrc = std::min(src,dest);
int thisDest = std::max(src,dest);
int eSrc = std::min(edge.src,edge.dest);
int eDest = std::max(edge.src,edge.dest);
if (thisSrc < eSrc) {
return true;
} else if (thisSrc > eSrc) {
return false;
} else {
return thisDest < eDest;
}
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
#include <set>
int main() {
Edge edge(0, 3);
std::set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
if (a == test.end()) {
std::cout << "edge not found." << std::endl;
} else {
std::cout << a->src << " " << a->dest << std::endl;
}
}
Output:
3 0
I want to check if a given point with x and yvalue is inside a vector of points:
bool inside_vector(int x, int y, vector<Point2i>& points)
{
for(vector<Point2i>::const_iterator it = points.begin();
it != points.end();
++it)
{
if(it->x == y && it->y == y)
{
return true;
}
}
return false;
}
Are there other approaches without the for loop?
You can use std::find or std::find_if with suitable functor to avoid writing your own loop. But you don't gain in terms of complexity: it is still O(n). For example,
bool operator==(const Point2i& lhs, const Point2i& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
Point2Di somePoint = Point2Di(x,y); // point to find
auto it = std::find(points.begin(), points.end(), somePoint);
or, without the equality operator,
auto it = std::find_if(points.begin(),
points.end(), [&somePoint](const Point2Di& p)
{return somePoint.x == p.x && somePoint.y == p.y;});
Assumming you have an operator== defined for your Point2i structure, you can use std::find(), like this:
std::vector<Point2i>::const_iterator findIt = std::find(
points.begin(),
points.end(),
Point2i(x, y));
I also assume you have a Point2i constructor that takes the two coordinates.
struct Cord
{
int x_cord;
int y_cord;
Cord(int x = 0,int y = 0):x_cord(x),y_cord(y) {}
bool operator < (const Cord& cord) const
{
if (x_cord == cord.x_cord)
{
return y_cord < cord.y_cord;
}
return x_cord < cord.x_cord;
}
bool operator == (const Cord& cord) const
{
return x_cord == cord.x_cord && y_cord == cord.y_cord;
}
};
std::set<Cord> cordRes,cordTmp;//initialized before
std::set<Cord> cordItersect;
std::set_intersection(cordRes.begin(),cordRes.end(),cordTmp.begin(),cordTmp.end(),cordRes.begin(),cordItersect.begin());
The compilation for above code fails.Any proposiotons how to use set_intersection correctly in the example?
Thanks
Well one problem is that set_intersection only takes five arguments. The other problem is that you need some mechanism to create the elements you are inserting to cordItersect. In your case that would be to use std::inserter.
std::set_intersection(cordRes.begin(), cordRes.end(),
cordTmp.begin(), cordTmp.end(),
std::inserter(cordItersect, cordItersect.end()));
Hi all I am a newbie to c++.
After compiling this program, I get an error msg saying .
assign3_3.cpp:120:9: error: could not convert 'sPair' from 'std::set<pairT, clas
scomp>' to 'std::set<pairT>'
here is my code.
#include <set>
#include <string>
#include <iostream>
using namespace std;
struct pairT
{
string first, second;
};
struct classcomp
{
bool operator() (const pairT &lhs, const pairT &rhs) const
{
if (lhs.first == rhs.first && lhs.second == rhs.second)
{
return 0;
}
else if (lhs.first < rhs.first)
{
return -1;
}
else if (lhs.first == rhs.first && lhs.second < rhs.second)
{
return -1;
}
else
{
return 1;
}
}
};
set<pairT> CartesianProduct(set<string> & one, set<string> & two);
int main()
{
string A = "ABC";
string B = "XY";
set<string> sA, sB;
sA.insert(&A[0]);
sA.insert(&A[1]);
sA.insert(&A[2]);
sA.insert(&B[0]);
sA.insert(&B[1]);
set<pairT> pT = CartesianProduct(sA, sB);
//for (set<pairT>::iterator it = pT.begin(); it != pT.end(); it++)
// cout << pT.find(it).first << pT.find(it).second << endl;
return 0;
}
set<pairT> CartesianProduct(set<string> &one, set<string> &two)
{
set<string>::iterator itA, itB;
pairT pT;
set<pairT, classcomp> sPair;
for (itA = one.begin(); itA != one.end(); itA++)
{
//cout << *itA << endl;
for(itB = two.begin(); itB != two.end(); itB++)
{
pT.first = *itA;
pT.second = *itB;
sPair.insert(pT);
}
}
return sPair;
}
First, I am not understanding about the making a comparison function for pairT.
If this is the case here, please explain.
I am having a trouble using set container please help thanks and merry christmas !
The comparator is part of the type. You must say set<pairT, classcomp> everywhere. Best to use a typedef.
In addition to what Kerrek SB said, your comparison function isn't correct.
The comparator required by std::set<std::pair> needs to follow the following logic:
if (lhs.first < rhs.first)
return true;
else if (lhs.first == rhs.first && lhs.second < rhs.second)
return true;
else
return false;
This can be expressed more compactly as:
return lhs.first < rhs.first ||
!(rhs.first < lhs.first) && lhs.second < rhs.second;
Fortunately, this is how std::pair::operator< is defined in the standard library. When you create a std::set<std::pair> this operator will be used by default so you don't have to provide your own.
I'm looking for a container that maps from a double to object pointers. However, each key is simply a range of doubles that would correspond to that object.
For example, there could be a key/value pair that's <(0.0 3.0), ptr>, or <(3.5 10.0), ptr2>
container[1.0] should return ptr, container[3.0] should also return ptr, and container[-1.0] should be undefined.
Is there any object with similar behaviour by default or will I have to implement it myself?
Edit
Here's the actual code that I've written, it might be easier to debug/offer advice on it.
// Behavior: A range is defined mathematically as (min, max]
class dblRange
{
public:
double min;
double max;
dblRange(double min, double max)
{
this->min = min;
this->max = max;
};
dblRange(double val)
{
this->min = val;
this->max = val;
};
int compare(const dblRange rhs)
{
// 1 if this > rhs
// 0 if this == rhs
//-1 if this < rhs
if (rhs.min == rhs.max && min == max)
{
/*if (min > rhs.min)
return 1;
else if (min == rhs.min)
return 0;
else
return -1;*/
throw "You should not be comparing values like this. :(\n";
}
else if (rhs.max == rhs.min)
{
if (min > rhs.min)
return 1;
else if (min <= rhs.min && max > rhs.min)
return 0;
else // (max <= rhs.min)
return -1;
}
else if (min == max)
{
if (min >= rhs.max)
return 1;
else if (min < rhs.max && min >= rhs.min)
return 0;
else // if (min < rhs.min
return -1;
}
// Check if the two ranges are equal:
if (rhs.min == min && rhs.max == max)
{
return 0;
}
else if (rhs.min < min && rhs.max <= min)
{
// This is what happens if rhs is fully lower than this one.
return 1;
}
else if (rhs.min > min && rhs.min >= max)
{
return -1;
}
else
{
// This means there's an undefined case. Ranges are overlapping,
// so comparisons don't work quite nicely.
throw "Ranges are overlapping weirdly. :(\n";
}
};
int compare(const dblRange rhs) const
{
// 1 if this > rhs
// 0 if this == rhs
//-1 if this < rhs
if (rhs.min == rhs.max && min == max)
{
/*if (min > rhs.min)
return 1;
else if (min == rhs.min)
return 0;
else
return -1;*/
throw "You should not be comparing values like this. :(\n";
}
else if (rhs.max == rhs.min)
{
if (min > rhs.min)
return 1;
else if (min <= rhs.min && max > rhs.min)
return 0;
else // (max <= rhs.min)
return -1;
}
else if (min == max)
{
if (min >= rhs.max)
return 1;
else if (min < rhs.max && min >= rhs.min)
return 0;
else // if (min < rhs.min
return -1;
}
// Check if the two ranges are equal:
if (rhs.min == min && rhs.max == max)
{
return 0;
}
else if (rhs.min < min && rhs.max <= min)
{
// This is what happens if rhs is fully lower than this one.
return 1;
}
else if (rhs.min > min && rhs.min >= max)
{
return -1;
}
else
{
// This means there's an undefined case. Ranges are overlapping,
// so comparisons don't work quite nicely.
throw "Ranges are overlapping weirdly. :(\n";
}
};
bool operator== (const dblRange rhs ) {return (*this).compare(rhs)==0;};
bool operator== (const dblRange rhs ) const {return (*this).compare(rhs)==0;};
bool operator!= (const dblRange rhs ) {return (*this).compare(rhs)!=0;};
bool operator!= (const dblRange rhs ) const {return (*this).compare(rhs)!=0;};
bool operator< (const dblRange rhs ) {return (*this).compare(rhs)<0;};
bool operator< (const dblRange rhs ) const {return (*this).compare(rhs)<0;};
bool operator> (const dblRange rhs ) {return (*this).compare(rhs)>0;};
bool operator> (const dblRange rhs ) const {return (*this).compare(rhs)>0;};
bool operator<= (const dblRange rhs ) {return (*this).compare(rhs)<=0;};
bool operator<= (const dblRange rhs ) const {return (*this).compare(rhs)<=0;};
bool operator>= (const dblRange rhs ) {return (*this).compare(rhs)>=0;};
bool operator>= (const dblRange rhs ) const {return (*this).compare(rhs)>=0;};
};
Right now I'm having trouble having the map accept a double as a key, even though the comparison operators are defined.
Here's some driving code that I'm using to test if it would work:
std::map<dblRange, int> map;
map[dblRange(0,1)] = 1;
map[dblRange(1,4)] = 2;
map[dblRange(4,5)] = 3;
map[3.0] = 4;
I mostly agree with Earwicker in that you can define a range. Now, I am in favor of implementing operators with the real meaning (do what basic types do: two ranges compare equal if both ranges ARE equal). Then you can use the third map parameter to pass it a comparison functor (or function) that solves your particular problem with this map.
// Generic range, can be parametrized for any type (double, float, int...)
template< typename T >
class range
{
public:
typedef T value_type;
range( T const & center ) : min_( center ), max_( center ) {}
range( T const & min, T const & max )
: min_( min ), max_( max ) {}
T min() const { return min_; }
T max() const { return max_; }
private:
T min_;
T max_;
};
// Detection of outside of range to the left (smaller values):
//
// a range lhs is left (smaller) of another range if both lhs.min() and lhs.max()
// are smaller than rhs.min().
template <typename T>
struct left_of_range : public std::binary_function< range<T>, range<T>, bool >
{
bool operator()( range<T> const & lhs, range<T> const & rhs ) const
{
return lhs.min() < rhs.min()
&& lhs.max() <= rhs.min();
}
};
int main()
{
typedef std::map< range<double>, std::string, left_of_range<double> > map_type;
map_type integer; // integer part of a decimal number:
integer[ range<double>( 0.0, 1.0 ) ] = "zero";
integer[ range<double>( 1.0, 2.0 ) ] = "one";
integer[ range<double>( 2.0, 3.0 ) ] = "two";
// ...
std::cout << integer[ range<double>( 0.5 ) ] << std::endl; // zero
std::cout << integer[ range<double>( 1.0 ) ] << std::endl; // one
std::cout << integer[ 1.5 ] << std::endl; // one, again, implicit conversion kicks in
}
You must be careful with equality and comparisons among double values. Different ways of getting to the same value (in the real world) can yield slightly different floating point results.
Create a class DoubleRange to store the double range, and implement the comparison operators on it. That way, std::map will do the rest for you, with the DoubleRange class as the key.
It is better to use Interval tree data structure. Boost has an implementation in Interval Container Library
One approach would be to calculate the "break points" before hand:
typedef vector< tuple<double, double, foo*> > collisionlist_t;
const collisionlist_t vec;
vec.push_back(make_tuple(0.0, 3.0, ptr));
vec.push_back(make_tuple(3.5, 10.0, ptr2));
// sort
std::map<double, foo*> range_lower_bounds;
for(collisionlist_t::const_iterator curr(vec.begin()), end(vec.end()); curr!=end; ++curr)
{
/* if ranges are potentially overlapping, put some code here to handle it */
range_lower_bounds[curr->get<0>()] = curr->get<2>();
range_lower_bounds[curr->get<1>()] = NULL;
}
double x = // ...
std::map<double, foo*>::const_iterator citer = range_lower_bounds.lower_bound(x);
Another suggestion: Use a mathematical transform to map the index from REAL to INT which can be directly compared.
If these ranges are multiple and dense there's also a structure known as an "interval tree" which may help.
Are the intervals open or closed or half open?
I will assumed closed. Note that the intervals cannot overlap by the definition of a map. You will also need splitting rules for when one inserts an over lapping interval. the rules need to decide where the split takes place and must take into account floating point epsilon.
this implementation uses map::lower_bound and does NOT use a class as the domain of the map
map::lower_bound returns an iterator to the first element in a map with a key value that is equal to or greater than that of a specified key. (ie the least key greater than or equal to K. An unfortunate choice of STL method names as it is the least upper bound of K.)
template <class codomain>
class RangeMap : private std::map<double,std::pair<double,codomain>{
public:
typedef double domain;
typedef std::map<double,std::pair<double,codomain>:: super;
typename super::value_type value_type;
protected:
static domain& lower(const value_type& v){
return v.first;
}
static domain& upper(const value_type& v){
return v.second.first;
}
static codomain& v(const value_type& v){
return v.second.second;
}
public:
static const domain& lower(const value_type& v){
return v.first;
}
static const domain& upper(const value_type& v){
return v.second.first;
}
static const codomain& v(const value_type& v){
return v.second.second;
}
static bool is_point(const value_type& vf) {
return lower(v) == upper(v);
}
static bool is_in(const domain& d,const value_type& vf) {
return (lower(v) <= d) && (d <= upper(v));
}
const_iterator greatest_lower_bound(const domain& d)const {
const_iterator j = super::lower_bound(d);
if(j!=end() && j->first==d) return j;//d is the lh side of the closed interval
//remember j->first >= d because it was lower but its the first
if(j==begin()) return end();//d < all intervals
--j; //back up
return j;
}
const_iterator find(domain& d) {
const_iterator j = greatest_lower_bound(d);
if (is_in(j,d)) return j;
return end();
}
iterator greatest_lower_bound(const domain& d) {
iterator j = super::lower_bound(d);
if(j!=end() && j->first==d) return j;//d is the lh side of the closed interval
//remember j->first >= d because it was lower but its the first
if(j==begin()) return end();//d < all intervals
--j; //back up
return j;
}
const_iterator find(domain& d) const{
iterator j = greatest_lower_bound(d);
if (is_in(j,d)) return j;
return end();
} //so much for find(d)
iterator find(domain& d){
iterator j = greatest_lower_bound(d);
if (is_in(j,d)) return j;
return end();
} //so much for find(d)
struct overlap: public std::exception{
};
bool erase(const double lhep,const double rhep);
//you have a lot of work regarding splitting intervals erasing when overlapped
//but that can all be done with erase, and insert below.
//erase may need to split too
std::pair<iterator,bool>
split_and_or_erase_intervals(const double lhep,
const double rhep,
const codomain& cd);
//the insert method - note the addition of the overwrtite
std::pair<iterator,bool>
insert(const double lhep,const double rhep,const codomain& cd,bool overwrite_ok){
if( find(lhep)!=end() || find(rhep)!=end() ) {
if(overwrite_ok){
return split_and_or_erase_intervals(const double lhep,
const double rhep,
const codomain& cd);
}
throw overlap();
}
return insert(value_type(lhep,pair<double,codomain>(rhep,cd)));
}
};
If your intervals must be non-overlapping, you must add some extra code to verify this property at insertion-time. Specifically, the property you wish to assert is that your new interval lies entirely within a range that was previously empty. An easy way to do this is to allow two types of ranges: "occupied" and "empty". You should begin by creating a single "empty" entry which covers the entire usable range. Insertion of a new "occupied" range requires:
(1) lookup some value within the new range.
(2) ensure that the returned range is empty, and wholly encompasses your new range. (This was the required assertion, above)
(3) modify the returned empty range so its end lies at the start of your new range.
(4) insert a new empty range that begins at the end of your new range, and ends at the old end of the returned range.
(5) insert your new range, confident that it is surrounded by empty-ranges.
(6) There may be additional corner-cases when inserting a new occupied range which has no empty space separating it from other occupied ranges.