Can I use vector as index in map structure in c++? - c++

I attempted to do something like this but it does not compile:
class point
{
public:
int x;
int y;
};
int main()
{
vector<point> vp1;
vector<point> vp2;
vector<point> vp3;
map < vector<point>, int > m;
m[vp1] = 1;
m[vp2] = 2;
m[vp3] = 3;
map < vector<point>, int >::iterator it;
for (it=m.begin(); it!=m.end(); it++)
{
cout<<m[it->first]<<endl;
}
return 0;
}

You can use anything as the index type into a std::map as long as it supports an operator< (which could could define as a free-standing function -- doesn't have to be a member function, as long as you can write a < b for a and b being instances of your type of interest) with the usual semantics (antireflexive, transitive, ...). Or, you can pass a binary function with the same semantics to use in lieu of <, if that suits you better.

You can, but the type used as a key in a map needs to be comparable, either using operator<, or using a comparison function/functor you supply as the third template parameter for the map type.

Yes, you can. Vectors, like all containers, are comparable. The resulting map will sort the vectors in lexicographic order.
The problem is that point is not comparable. You have to define a sort order for points, and then this will in turn define lexicographic order over vector<point>.
class point
{
public:
int x;
int y;
};
bool operator<( point const &l, point const &r ) {
return l.x < r.x? true
: r.x < l.x? false
: l.y < r.y;
}
A simpler solution is to use std::pair instead of defining your own point.
typedef pair< int, int > point; // point::first = x, point::second = y
// pair is already comparable; order defined as in previous example
typedef vector<point> pointvec; // OK

You haven't defined a function to compare a vector<point> Maps make requiremets of keys checking of equivalence and comparison.

You have to declare the operator<. It would look like this (please keep in mind, that the three vectors in your sample code actually look the same):
bool operator<(const vector<point>& left, const vector<point>& right)
{
return left.size() < right.size();
}

Related

C++ behavior unexpected of Set of class objects

For example, take a std::set of std::pair<int,int>, if you insert 2 pairs, {1,1} and {1,2}, both of them will be inserted in the set, however when i implemented a pair class, this behaviour is not seen. Only one of them gets inserted in the set. Please explain why?
#include <bits/stdc++.h>
using namespace std;
class PAIR {
public:
int x, y;
bool operator<(const PAIR& p) const { return x < p.x; }
};
int main() {
set<PAIR> s;
s.insert({ 1,1 });
s.insert({ 1,2 });
cout << s.size();
}
The output comes out to be 1, unlike i expected
std::set uses operator< for ordering and equivalence (it assumes equivalence when a<b and a>b are both false).
So with an operator< like x < p.x you're saying that only x is participating in comparison and y doesn't matter.
To use both x and y, the comparison should look more like:
bool operator<(const PAIR& p) const {
return std::tie(x, y) < std::tie(p.x, p.y);
}
A set can only hold unique values. It uses operator< to determine uniqueness.
For two items a and b, if (!(a<b) && !(b<a)) then they are considered equivalent.
Your operator< only considers the x member of your pair, so the y member is completely ignored for purposes of your set.

std::set different comparer for inserting and ordering

I need a structure in which I can insert elements, have no duplicate, use a custom comparer and have the smallest element first. I tried using std::priority_queue, but the problem is that I get a lot of duplicates and I run out of space. So I thought about using std::set : std::set< std::pair<Coordinates, int>, Compare> positions; where
Coordinates
{
public:
Coordinates(int x = 0, int y = 0, char tool = 'T') : x(x), y(y), tool(tool) {}
public:
int x, y;
char tool;
};
class Compare
{
public:
bool operator() (const std::pair<Coordinates, int>& c1, const std::pair<Coordinates, int>& c2) const
{
return c1.second < c2.second;
}
};
I want the elements to be sorted based on the second element of pair, which this implementation is doing, but the problem is that it is using the same comparer when inserting new pairs and I get duplicates. My question is: Is it possible to make the std::set to not allow duplicates also to order the elements based on the second element of pair?
Edit: Eliminated some code that was not necessary and changed in Compare > with <
Using your Comparer the set will contain only unique values of the int, since Coordinates isn't participating in the comparison at all.
std::set uses operator < for sorting as well as equality; equality is determined as !(a<b || b<a). Therefore operator < should take into account every attribute which makes the element unique.
You can specialize std::less for your type like this:
namespace std {
template<>
struct less<pair<Coordinates, int>> {
bool operator()(const pair<Coordinates, int>& a, const pair<Coordinates, int>& b) const {
return tie(a.second, a.first.x, a.first.y) < tie(b.second, b.first.x, b.first.y);
}
};
}
Then std::set< std::pair<Coordinates, int>> positions; should work.
The issue here is that since you only look at second in you comparator, you can only store pairs that have unique values for second. This is because the set only uses the comparator to compare the elements. It doesn't use your operator == to check for equality but instead does cmp(a, b) == cmp(b, a)1 to test if the values are equal.
If you wan to sort by second, but allow other points with the same second but different other values then you need to add those values into you comparator. The easiest way to do that is to use std::tie to build a couple of tuples and use the tuples operator < which "does the right thing". That would look like
class Compare
{
public:
bool operator() (const std::pair<Coordinates, int>& c1, const std::pair<Coordinates, int>& c2) const
{
return std::tie(c1.second, c1.first.x, c1.first.y) < std::tie(c2.second, c2.first.x, c2.first.y);
}
};
1: If a is not less then b, and b is not less than a then a and b must be equal
As stated, the issue was that you only looked at the second member of the pair, so the set didn't care if the Coordinates were different. You simply needed to include the Coordinates in your comparison.
Unlike the other answers, this one utilizes a lambda for the comparison. I prefer it over std::tie and mucking around with std overrides. It also saves you the trouble of writing up a functor yourself like you did with your Compare class.
#include <iostream>
#include <set>
class Coordinates {
public:
Coordinates(int x = 0, int y = 0, char tool = 'T') : x(x), y(y), tool(tool) {}
int x, y;
char tool;
};
int main() {
using CoordPair = std::pair<Coordinates, int>;
auto compare = [](const CoordPair& a, const CoordPair& b) {
if (a.second != b.second)
return a.second < b.second;
// Replace this with some method of comparing Coordinates
return a.first.x != b.first.x || a.first.y != b.first.y;
};
std::set<std::pair<Coordinates, int>, decltype(compare)> list(compare);
list.emplace(Coordinates(1, 1), 2);
list.emplace(Coordinates(2, 0), 2);
list.emplace(Coordinates(1, 1), 3);
list.emplace(Coordinates(1, 1), 2); // Shouldn't show up
for (auto i : list)
std::cout << '(' << i.first.x << ", " << i.first.y << ", " << i.first.tool
<< ')' << ", " << i.second << '\n';
}
Your C++ version wasn't specified, this needs at least C++11.

STL priority_queue of pairs<int, struct> error

Finding a shortest path in a grid and struggling to set up priority queue properly.
struct position{
int row;
int col;
position* parent;
position(int a, int b):row(a),col(b), parent(nullptr){}
};
vector<position>vec;
priority_queue<pair<int, position>, vector<pair<int, position>>, greater<pair<int, position>>>pq;
int distance = 0;
position *t = new p(0,0);
pq.push(make_pair(distance, t));
Getting this error:
no matching function for call to ‘std::priority_queue, std::vector >, std::greater > >::push(std::pair)’
pq.push(make_pair(distance, t));
You need to write a functor ( or use a lambda) to compare the distance - position pair, std::greater won't automatically do it for you. Try this snippet:
struct position {
int row;
int col;
position* parent;
position(int a, int b) :row(a), col(b), parent(nullptr) {}
};
typedef std::pair<int, position> dist_pos_t;
class compare
{
public:
bool operator()(const dist_pos_t& lhs, const dist_pos_t& rhs)
{
return rhs.first < lhs.first;
}
};
std::priority_queue<dist_pos_t, std::vector<dist_pos_t>, compare >pq;
int main() {
int distance = 0;
position *t = new position(0, 0);
pq.push(std::make_pair(distance, *t));
}
Here Declaration of Priority Queue does not match with what you are trying to push.
Declaration should be something like
priority_queue<pair<obj1,obj2>pq;
obj1/obj2 can be anything like int or pair<obj,obj>
After such declaration you can use
pq.push(make_pair(obj1,obj2))
There are two major issues in your code.
First, your priority_queue is of std::pair<int, position>, but you are trying to push in a std::pair<int, position*>.
Second, std::greater<T> depends on the > operator of the underlying type T. In your case, it's std::pair<int, position>, whose > operator depends on the < operator of position (See this reference). You need to provide < for position, or, you can use a custom compare functor type.

Any alternative for pairs?

I have many points (a,b) and I stored x coordinate in a[] and y coordinate in b[]. Now I need to sort these points wrt x-coordinate or y-coordinate. I know that there is concept of pairs in C++ but is there any better way of doing this. Please give answers in C/C++.
You can store the pair of coordinates using std::pair<int, int>, or as the answer by #Gopi indicates by a struct.
A collection of either of those can be sorted by the X coordinate or by the Y coordinate by using a lambda function, a functor, or a global function.
// A vector of vertices.
std::vector<std::pair<int, int>> vertices;
// Sort the vertices by X coordinates using a lambda function to order them
std::sort(vertices.begin(), vertices.end(),
[](auto const& a, auto const& b) { return a.first < b.first; });
// Sort the vertices by Y coordinates using a lambda function to order them
std::sort(vertices.begin(), vertices.end(),
[](auto const& a, auto const& b) { return a.second < b.second; });
struct vertex
{
int x;
int y;
};
Then sort the structures accordingly.
You can use a struct as pointed out and shown in other answers. However, if you define your own struct you will need to define a comparator function to use with the sorting algorithm or overload the < operator.
The advantage of using std::pair is that you won't need to define a comparator because std::pair overloads the operator < to sort by first element first then second element.
See this answer for an example.
The best way is struct as the answer by #Gopi. For lexicographical sorting you can use std::tie (http://en.cppreference.com/w/cpp/utility/tuple/tie).
struct vertex
{
int x;
int y;
bool less_x(const struct vertex& b) const { return std::tie(x,y) < std::tie(b.x, b.y); }
bool less_y(const struct vertex& b) const { return std::tie(y,x) < std::tie(b.y, b.x); }
};
int c = x*n + y where, n>x and n>y
x=c/n
y=c%n
When you need x simply c/n will give x and for y use c%n gives y.
Note: Works for positive coordinates only

C++ how to sort vector<class *> with operator <

i have
class c1{
public:
int number;
c1()
{
number=rand()%10;
}
bool operator < (c1 *w)
{
return number < w->number;
}
};
vector<c1*> vec = { ... }
sort(vec.begin(),vec.end())
why it dosent sort ?
but if we had
bool operator < (c1 w)
{
return number < w.number;
}
and
vector<c1> vec = { ... }
it would have been sorted !
The most straightforward approach is to define a function
bool c1_ptr_less( c1 const *lhs, c1 const *rhs ) {
return lhs->something < rhs->something;
}
std::sort( vec.begin(), vec.end(), & c1_ptr_less );
What I would suggest is a generic functor to take care of all pointer arrays
struct pointer_less {
template< typename T >
bool operator()( T const *lhs, T const *rhs ) const
{ return * lhs < * rhs; }
};
std::sort( vec.begin(), vec.end(), pointer_less() );
Armed with this, define the usual c1::operator< ( const c1 & ) and likewise for other classes.
Generally, best practice is to avoid pointers entirely, including arrays of pointers.
To answer your title question, you can't.
Pointers are built-in types, you cannot override operators where all operands are built-in types.
Luckily, there's an overload of std::sort that allows you to specify a comparison function (or functor) so the operator< isn't used.
bool operator < (c1 *w) compares a c1 to a c1 * - Your sort compares a c1 * to a c1 *
You need to pass a compare function to std::sort:
bool compare_c1 (c1* x, c1* y)
{
return *x < y;
}
std::sort(v.begin(), v.end(), compare_c1);
Or if you are using GCC >= 4.5 or Visual Studio 2010 (I'm do not know sure about Intel compiler) you can use lambdas (they are part of the C++0x standard):
std::sort(v.begin(), v.end(), [] (c1* x, c1* y) { return *x < y; });
Add a external operator< and keep de original one:
bool operator<(c1* a, c1* b) { return *a < *b; }
Now sort will work on the vector.
phimuemue's answer sums it up, I'll just add that, as a workaround, you can create a wrapper class that contains only one member - a pointer to c1, and then overload its operator <. Then you could sort a vector of object of that class.
And in your example, vector<c1*> is sorted. Just not to the
criteria you seem to want: by default, sort uses
std::less<T> as the ordering criteria, and std::less<ci*>
compares the pointers (which is what you'd expect). If you
don't want the default criteria, then you have to pass a third
argument to sort, a predicate defining the ordering you want.
And of course, your member operator<(c1*) will only be called
when you compare a c1 with a ci* (and only if the c1 is an
rvalue). Such operators are very, very rare---normally, both
sides of a < operator should take the same type (and should be
const, since a < operator which modifies the values of the
objects it compares would be surprising, to say the least).