I wanted to define a datastructure like:
struct node {
int x_coordinate;
int y_coordinate;
// some variables
};
map<node, priority_queue<node> > M;
// or lets say
map<node, set<node> > M
The problem I am facing is I don't know how to write it's custom comparator
Also do you think if it is possible to sort the priority_queue based on the distance from the it's key node. For example let's say if I have key node with x_coordinate=0 and y_coordinate=0, and I want to insert (8,6),(4,3),(15, 9),(0,1).
So priority_queue would be something like (0,1) (4,3) (8,6) (15,9)
P.S. : I have used following code after discussion with people but it's still giving compilation error
struct Node {
Node (int a, int b) {
x = a;
y = b;
}
int x, y;
};
struct cmp {
Node node(0,0); // this node corresponds to the node that came from map key
cmp(Node node) {
this->node = node;
}
int getDistance (Node a, Node b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
bool operator () (Node node1, Node node2) {
return (getDistance(node, node1) < getDistance(node, node2));
}
};
int main() {
auto mapCmp = [&] (Node node1, Node node2){
return node1.x < node2.x and (node1.x == node2.x and node1.y < node2.y);
};
map<Node, priority_queue<Node, vector<Node>, cmp(Node)>, decltype(mapCmp)> myMap(mapCmp);
myMap[Node(0,0)].push(Node(2,4));
myMap[Node(0,0)].push(Node(1,3));
myMap[Node(0,1)].push(Node(2,4));
myMap[Node(0,1)].push(Node(1,3));
return 0;
}
Error Snapshot:
Interesting problem. The latter portion (priority order based on the mapped-from key value) presents the real challenge.
Map Custom Key Comparison
The basic three methods from key comparison to a map are:
Provide an operator < member override for the map key type, OR
Provide a functor type as the comparator for the map, OR
Provide a free-function.
The most common of these is the first, simply because it's the easiest to implement and visualize. The default comparator for a map is std::less<K> where K is the key type. The standard library std::less defaults to attempt an operator < comparison, in effect it does this:
bool isLess = (a < b)
where a and b are both your key type. Therefore, a simple member const operator < overload will fit the requirements and get you what you want:
struct Node {
Node(int a=0, int b=0)
: x(a), y(b)
{
}
int x, y;
// called by default std::less
bool operator <(const Node& rhs) const
{
return (x < rhs.x) || (!(rhs.x < x) && y < rhs.y);
}
// simple distance calculation between two points in 2D space.
double distanceFrom(Node const& node) const
{
return std::sqrt(std::pow((x - node.x), 2.0) + std::pow((y - node.y), 2.0));
}
friend std::ostream& operator <<(std::ostream& os, Node const& node)
{
return os << '(' << node.x << ',' << node.y << ')';
}
};
This supports a strict weak order and will suffice. The other options are a little bit more complicated, but not by much. I'll not cover them here, but there are pleny of questions on SO that will.
Note: I added the distanceFrom and operator << members and friend for later use in the final sample; you'll see them later.
Priority Queue Instance Comparison Override
Never done this before, but if there is an easier way I'm certainly open to suggestion. The problem with using a template-type comparator override for your priority queue is you can't really do it. You want each queue to be ordered based on distance to origin, where the origin is the map key for that queue. That means each comparison object must somehow be fed the origin of the map key, and you can't do that with a template-type override (i.e. a compile-time thing).
What you can do, however, is provide an instance comparison override. std::priority_queue allows you to provide a custom comparison object where the queue is created (in our case, when it is inserted into the map as the mapped-to target). A little massaging and we come up with this:
First, a priority functor that takes either no args or a Node.
// instance-override type
struct NodePriority
{
NodePriority() = default;
NodePriority(Node node)
: key(std::move(node))
{
}
// compares distance to key of two nodes. We want these in
// reverse order because smaller means closer means higher priority.
bool operator()(const Node& lhs, const Node& rhs) const
{
return rhs.distanceFrom(key) < lhs.distanceFrom(key);
}
private:
Node key;
};
using NodeQueue = std::priority_queue<Node, std::deque<Node>, NodePriority>;
The using NodeQueue will save us a ton of typing in the sample that follows.
Sample
Using the above we are now ready to build our map and queue. The following creates a random list of ten nodes, each of which carry and x,y in the range of 1..9. We then use those nodes to build ten priority queues, one for each map entry we're creating. The map entries are the diagonal slice (i.e. (1,1), (2,2), (3,3), etc.). With the same the same ten random elements we should see different priority queue orderings as we report the final results.
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <queue>
#include <map>
#include <random>
struct Node {
Node(int a=0, int b=0)
: x(a), y(b)
{
}
int x, y;
// called by default std::less
bool operator <(const Node& rhs) const
{
return (x < rhs.x) || (!(rhs.x < x) && y < rhs.y);
}
// simple distance calculation between two points in 2D space.
double distanceFrom(Node const& node) const
{
return std::sqrt(std::pow((x - node.x), 2.0) + std::pow((y - node.y), 2.0));
}
friend std::ostream& operator <<(std::ostream& os, Node const& node)
{
return os << '(' << node.x << ',' << node.y << ')';
}
};
// instance-override type
struct NodePriority: public std::less<Node>
{
NodePriority() = default;
NodePriority(Node node)
: key(std::move(node))
{
}
// compares distance to key of two nodes. We want these in
// reverse order because smaller means closer means higher priority.
bool operator()(const Node& lhs, const Node& rhs) const
{
return rhs.distanceFrom(key) < lhs.distanceFrom(key);
}
private:
Node key;
};
using NodeQueue = std::priority_queue<Node, std::deque<Node>, NodePriority>;
int main()
{
std::mt19937 rng{ 42 }; // replace with { std::random_device{}() } for random sequencing;
std::uniform_int_distribution<> dist(1, 9);
std::map<Node, NodeQueue> myMap;
// generate ten random points
std::vector<Node> pts;
for (int i = 0; i < 10; ++i)
pts.emplace_back(Node(dist(rng), dist(rng)));
for (int i = 0; i < 10; ++i)
{
Node node(i, i);
myMap.insert(std::make_pair(node, NodeQueue(NodePriority(node))));
for (auto const& pt : pts)
myMap[node].emplace(pt);
}
// enumerate the map of nodes and their kids
for (auto& pr : myMap)
{
std::cout << pr.first << " : {";
if (!pr.second.empty())
{
std::cout << pr.second.top();
pr.second.pop();
while (!pr.second.empty())
{
std::cout << ',' << pr.second.top();
pr.second.pop();
}
}
std::cout << "}\n";
}
}
Note: the pseudo random generator is always seeded with 42 to have a repeatable sequence. When you decide to turn this loose with non-repeatable testing just replace that seed with the one provided in the comment next to the declaration.
Output (yours will vary, of course).
(0,0) : {(3,1),(5,1),(3,5),(5,3),(5,4),(5,5),(1,9),(6,7),(5,8),(6,8)}
(1,1) : {(3,1),(5,1),(3,5),(5,3),(5,4),(5,5),(6,7),(1,9),(5,8),(6,8)}
(2,2) : {(3,1),(3,5),(5,1),(5,3),(5,4),(5,5),(6,7),(5,8),(1,9),(6,8)}
(3,3) : {(3,1),(3,5),(5,3),(5,4),(5,5),(5,1),(6,7),(5,8),(6,8),(1,9)}
(4,4) : {(5,4),(5,5),(3,5),(5,3),(5,1),(3,1),(6,7),(5,8),(6,8),(1,9)}
(5,5) : {(5,5),(5,4),(3,5),(5,3),(6,7),(5,8),(6,8),(5,1),(3,1),(1,9)}
(6,6) : {(6,7),(5,5),(6,8),(5,4),(5,8),(3,5),(5,3),(5,1),(1,9),(3,1)}
(7,7) : {(6,7),(6,8),(5,8),(5,5),(5,4),(3,5),(5,3),(1,9),(5,1),(3,1)}
(8,8) : {(6,8),(6,7),(5,8),(5,5),(5,4),(3,5),(5,3),(1,9),(5,1),(3,1)}
(9,9) : {(6,8),(6,7),(5,8),(5,5),(5,4),(3,5),(5,3),(1,9),(5,1),(3,1)}
I'l leave you to verify the accuracy of the distanceFrom calculations, but hopefully you get the idea.
struct cmp {
cmp(Node node) { this->node = node; }
bool operator () (const Node& node1, const Node& node2) {
return (getDistance(node, node1) < getDistance(node, node2));
}
Node node; // this node corresponds to the node that came from map key
};
You can declare map as
std::map<Node, priority_queue<Node, vector<Node>, cmp(Node)>> myMap;
The below line makes the above written comparator different from regular comparators because you want to pass the key of the map inside the comparator.
cmp(Node node) { this->node = node; }
I have not compiled the above. If any errors should work with trivial fix. I think I have given enough code to unblock you. As an exercise, try using lambda instead of a separate comparator function.
Quite often I have two variables foo1 and foo2 which are numeric types. They represent the bounds of something.
A user supplies values for them, but like a recalcitrant musician, not necessarily in the correct order!
So my code is littered with code like
if (foo2 < foo1){
std::swap(foo2, foo1);
}
Of course, this is an idiomatic sort with two elements not necessarily contiguous in memory. Which makes me wonder: is there a STL one-liner for this?
I suggest to take a step back and let the type system do the job for you: introduce a type like Bounds (or Interval) which takes care of the issue. Something like
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
This not only centralizes the swap-to-sort code, it also helps asserting the correct order very early on so that you don't pass around two elements all the time, which means that you don't even need to check the order so often in the first place.
An alternative approach to avoid the issue is to express the boundaries as a pair of 'start value' and 'length' where the 'length' is an unsigned value.
No, but when you notice you wrote the same code twice it's time to write a function for it:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
std::minmax returns pair of smallest and largest element. Which you can use with std::tie.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
Note that this isn't the same as the if(a < b) std::swap(a,b); version. For example this doesn't work with move-only elements.
if the data type of your value that you're going to compare is not already in c++. You need to overload the comparison operators.
For example, if you want to compare foo1 and foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
If your value is some type of int, or double. Then you can use the std::list<>::sort member function.
For example:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}
I have following structure
enum quality { good = 0, bad, uncertain };
struct Value {
int time;
int value;
quality qual;
};
class MyClass {
public:
MyClass() {
InsertValues();
}
void InsertValues();
int GetLocationForTime(int time);
private:
vector<Value> valueContainer;
};
void MyClass::InsertValues() {
for(int num = 0; num < 5; num++) {
Value temp;
temp.time = num;
temp.value = num+1;
temp.qual = num % 2;
valueContainer.push_back(temp);
}
}
int MyClass::GetLocationForTime(int time)
{
// How to use lower bound here.
return 0;
}
In above code I have been thrown with lot of compile errors. I think I am doing wrong here I am new to STL programming and can you please correct me where is the error? Is there better to do this?
Thanks!
The predicate needs to take two parameters and return bool.
As your function is a member function it has the wrong signature.
In addition, you may need to be able to compare Value to int, Value to Value, int to Value and int to int using your functor.
struct CompareValueAndTime
{
bool operator()( const Value& v, int time ) const
{
return v.time < time;
}
bool operator()( const Value& v1, const Value& v2 ) const
{
return v1.time < v2.time;
}
bool operator()( int time1, int time2 ) const
{
return time1 < time2;
}
bool operator()( int time, const Value& v ) const
{
return time < v.time;
}
};
That is rather cumbersome, so let's reduce it:
struct CompareValueAndTime
{
int asTime( const Value& v ) const // or static
{
return v.time;
}
int asTime( int t ) const // or static
{
return t;
}
template< typename T1, typename T2 >
bool operator()( T1 const& t1, T2 const& t2 ) const
{
return asTime(t1) < asTime(t2);
}
};
then:
std::lower_bound(valueContainer.begin(), valueContainer.end(), time,
CompareValueAndTime() );
There are a couple of other errors too, e.g. no semicolon at the end of the class declaration, plus the fact that members of a class are private by default which makes your whole class private in this case. Did you miss a public: before the constructor?
Your function GetLocationForTime doesn't return a value. You need to take the result of lower_bound and subtract begin() from it. The function should also be const.
If the intention of this call is to insert here, then consider the fact that inserting in the middle of a vector is an O(N) operation and therefore vector may be the wrong collection type here.
Note that the lower_bound algorithm only works on pre-sorted collections. If you want to be able to look up on different members without continually resorting, you will want to create indexes on these fields, possibly using boost's multi_index
One error is that the fourth argument to lower_bound (compareValue in your code) cannot be a member function. It can be a functor or a free function. Making it a free function which is a friend of MyClass seems to be the simplest in your case. Also you are missing the return keyword.
class MyClass {
MyClass() { InsertValues(); }
void InsertValues();
int GetLocationForTime(int time);
friend bool compareValue(const Value& lhs, const Value& rhs)
{
return lhs.time < rhs.time;
}
Class keyword must start from lower c - class.
struct Value has wrong type qualtiy instead of quality
I dont see using namespace std to use STL types without it.
vector<value> - wrong type value instead of Value
Etc.
You have to check it first before posting here with such simple errors i think.
And main problem here that comparison function cant be member of class. Use it as free function:
bool compareValue(const Value lhs, const int time) {
return lhs.time < time ;
}
class is the keyword and not "Class":
class MyClass {
And its body should be followed by semicolon ;.
There can be other errors, but you may have to paste them in the question for further help.
You just want to make compareValue() a normal function. The way you have implemented it right now, you need an object of type MyClass around. The way std::lower_bound() will try to call it, it will just pass in two argument, no extra object. If you really want it the function to be a member, you can make it a static member.
That said, there is a performance penalty for using functions directly. You might want to have comparator type with an inline function call operator:
struct MyClassComparator {
bool operator()(MyClass const& m0, MyClass const& m1) const {
return m0.time < m1.time;
}
};
... and use MyClassComparator() as comparator.
My priority queue declared as:
std::priority_queue<*MyClass> queue;
class MyClass {
bool operator<( const MyClass* m ) const;
}
is not sorting the items in the queue.
What is wrong? I would not like to implement a different (Compare) class.
Answer summary:
The problem is, the pointer addresses are sorted. The only way to avoid this is a class that 'compares the pointers'.
Now implemented as:
std::priority_queue<*MyClass, vector<*MyClass>, MyClass::CompStr > queue;
class MyClass {
struct CompStr {
bool operator()(MyClass* m1, MyClass* m2);
}
}
Give the que the Compare functor ptr_less.
If you want the ptr_less to be compatible with the rest of the std library (binders, composers, ... ):
template<class T>
struct ptr_less
: public binary_function<T, T, bool> {
bool operator()(const T& left, const T& right) const{
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less<MyClass*> > que;
Otherwise you can get away with the simplified version:
struct ptr_less {
template<class T>
bool operator()(const T& left, const T& right) const {
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less > que;
The operator <() you have provided will compare a MyClass object with a pointer to a MyClass object. But your queue contains only pointers (I think). You need a comparison function that takes two pointers as parameters.
All this is based on some suppositions - please post your actual code, using copy and paste.
Since your priority_queue contains only pointer values, it will use the default comparison operator for the pointers - this will sort them by address which is obviously not what you want. If you change the priority_queue to store the class instances by value, it will use the operator you defined. Or, you will have to provide a comparison function.
Not sure about the priority queue stuff because I've never used it but to do a straight sort, you can do this:
class A
{
friend struct ComparePtrToA;
public:
A( int v=0 ):a(v){}
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return a1->a < a2->a;}
};
#include <vector>
#include <algorithm>
int _tmain(int argc, _TCHAR* argv[])
{
vector<A*> someAs;
someAs.push_back(new A(1));
someAs.push_back(new A(3));
someAs.push_back(new A(2));
sort( someAs.begin(), someAs.end(), ComparePtrToA() );
}
Note the memory leaks, this is only an example...
Further note: This is not intended to be an implementation of priority queue! The vector is simply an example of using the functor I created to compare two objects via their pointers. Although I'm aware of what a priority queue is and roughly how it works, I have never used the STL features that implement them.
Update: I think TimW makes some valid points. I don't know why he was downvoted so much. I think my answer can be improved as follows:
class A
{
public:
A( int v=0 ):a(v){}
bool operator<( const A& rhs ) { return a < rhs.a; }
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return *a1 < *a2;}
};
which is cleaner (especially if you consider having a container of values rather than pointers - no further work would be necessary).