2

I am trying to overload the > operator so I can do this for a priority queue:

priority_queue<Node, vector<Node>, greater<Node> > unexplored_nodes;

I would like to use it as a min-heap.

This is the code for the Node struct (I know, it's not best to have a struct with public variables, but I just wanted something quick and dirty):

struct Node {
  string repr;
  float d;
  vector<pair<Node, float> > neighbors;
  Node(string repr) {
    this->repr = repr;
    this->d = FLT_MAX;
  }

  // **All three of these forms yield errors**
  // Compiles without push() call below, but yields "invalids operands to binary expression" if I do have the push() call
  //bool operator()(const Node* lhs, const Node* rhs) const {
  //  return lhs->d > rhs->d;
  //}

  // Compiles without push() call below, but yields "invalids operands to binary expression" if I have do the push() call
  bool operator>(const Node &rhs) {
    return d > rhs.d;
  }

  // Error regardless of priority queue below: overloaded 'operator>' must be a binary operator (has 3 parameters)
  //bool operator>(const Node &lhs, const Node &rhs) {
  // return lhs.d > rhs.d;
  //}
};

void foo(const vector<Node> &list) {
  priority_queue<Node, vector<Node>, greater<Node> > q;
  q.push(list[0]); // this causes the 1st & 2nd overload attempt in the struct to have the "invalid operands" error
}

This is how I am compiling it:

clang++ -std=c++11 -stdlib=libc++ thefile.cc

In all 3 of the ways I tried, some error appeared (commented in the code). I had looked at Creating Min Heap from STL Priority Queue for ways to implement it (I tried the one by larsmans), but they haven't worked.

If anyone can help, I would appreciate it. (Also if you have a better way to use the priority queue as a min heap that avoids operator overloading, that would be good too... this is the main purpose.)

Community
  • 1
  • 1
dmonopoly
  • 3,251
  • 5
  • 34
  • 49

1 Answers1

5

You must mark the operator as const:

 bool operator> (const Node &rhs) const {
   return d > rhs.d;
 }

EDIT

If you don't want to overload operators, you can provide your own comparator to the queue:

struct Comparator
{
  bool operator() (const Node &lhs, const Node &rhs) const
  {
    return lhs.d > rhs.d;
  }
};

void foo(const vector<Node> &list) {
  priority_queue<Node, vector<Node>, Comparator> q;
  q.push(list[0]);
}

EDIT 2

Here's how you could use a custom map:

struct Comparator
{
  typedef std::map<Node, float> Map;

  explicit Comparator(const Map &map) : map(&map) {}

  bool operator() (const Node &lhs, const Node &rhs) const
  {
    return map->find(lhs)->second > map->find(rhs)->second;
  }

private:
  const Map *map;
};

void foo(const vector<Node> &list, const Comparator::Map &map) {
  priority_queue<Node, vector<Node>, Comparator> q(Comparator(map));
  q.push(list[0]);
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Just found this after posting the question >_> thanks for the quick response. The reason is because rhs is const, or is it a general rule to always have that? – dmonopoly Sep 13 '13 at 17:15
  • 2
    @dmonopoly It's a requirement on the comparator used by the priority queue. C++11, `[alg.sorting]§2`: "It is assumed that `comp` will not apply any non-constant function through the dereferenced iterator." – Angew is no longer proud of SO Sep 13 '13 at 17:17
  • @dmonopoly I've also added an option using a custom comparator instead of operator overloads. – Angew is no longer proud of SO Sep 13 '13 at 17:21
  • Oh nice, thanks! About the custom comparator: Suppose I had a map or some other data structure from Node objects to floats. Could I use this map in the custom comparator to compare Nodes? Ideally this would make more sense than my ad hoc "float d"... I wanted it to store the shortest path to that node from somewhere else, but it doesn't make sense to have that float there. I just didn't know how to pass the map to a custom comparator... – dmonopoly Sep 13 '13 at 17:29
  • 1
    @dmonopoly I've added a variant using a map. – Angew is no longer proud of SO Sep 13 '13 at 17:37
  • From a design POV, would you recommend using this more complex comparator with a map, or to stay simple and avoid things like this in C++? Thanks again - phenomenal answer. – dmonopoly Sep 13 '13 at 17:44
  • @dmonopoly If you need to prioritize according to data stored in a map, use the map-based comparator. There's nothing wrong with that. Of course, you should consider proper placement of the typedefs, arguments etc. - these were just added quickly to show the intention. In production code, `Map` should most definitely not be a member typedef of `Comparator`. Perhaps encapsulate the map in a class of your own, which will also provide the comaparator. Depends on your particular situation, really. – Angew is no longer proud of SO Sep 13 '13 at 17:50