简体   繁体   中英

c++ - Priority Queue - How does it work internally?

Say I have this declaration of a priority queue:

    struct orderByRewards{

    bool operator() (pair<int,pair<int,int> > a, pair<int, pair<int, int> > b){
        return a.first < b.first;
    }
};

priority_queue<pair<int,pair<int,int> >, vector<pair<int,pair<int,int> > >, orderByRewards> Q;

I was wondering if anybody could take their time and explain me how does the compiler interpret the compare class.

  • Why do I need to overload the () operator ?
  • Also, where's the () operator used in its comparing process ?

It feels a little weird, especially since I am not really comfortable with templates and all OOP concepts.

Why do we need to declare the type of a single object and the container type ?

You are not required to overfload the operator(). You can declare your custom method:

typedef bool (*comp)(int,int);
bool compare(int a, int b)
{
   return (a<b);
}
int main()
{
    std::priority_queue<int,std::vector<int>, comp> pq(compare);
    return 0;
}

Updated : As @WhozCraig pointed out: It is possible to use this object without overloading the operator() but the compiler will face an easier situation inlining operator() comparison function rather than runtime-provided dereferenced comparison function

You're essentially asking about function objects (or functors). A function object is one that overloads operator() . You can use such an object as though it were a function. The standard provides a few comparison functors (like your orderByRewards ). For example, std::less looks something like this:

template <class T>
struct less {
  constexpr bool operator()(const T &lhs, const T &rhs) const 
  {
    return lhs < rhs;
  }
};

As we can see, the overloaded operator() just compares the two arguments using < and then returns the boolean result. To use this, you need to create an object of type std::less and then use the function call syntax on it:

std::less<int> compare;
assert(compare(5, 7) == true);

Even though compare is an object, we were able to use it like a function in compare(5, 7) .

So now we know that your type orderByRewards is a function object type. You are passing it as a template type argument of std::priority_queue . The implementation of std::priority_queue can then create objects of this comparison function object when it needs to compare elements within the queue.

Consider a simpler example:

template <typename T, typename Comp>
struct foo {
  void bar(T a, T b) {
    Comp compare;
    if (compare(a, b)) {
      std::cout << "True" << std::endl;
    } else {
      std::cout << "False" << std::endl;
    }
  }
};

It's a silly example, but it gets the point across. We can use this like so:

foo<int, std::less<int>> my_foo;
my_foo.bar(5, 7); // Will print true

We were able to configure foo , by passing it some arbitrary comparison functor type, that its member function bar was able to instantiate and use.

So in the same way, you are configuration std::priority_queue by giving it a comparison functor type that it can use to order elements within the queue. This is how it determines priority between elements. In fact, the default template type argument for std::priority_queue is std::less .

Perhaps it would make the most sense to look at the definition of std::priority_queue and work from there.

template <class T, class Container = vector<T>, 
          class Compare = less<typename Container::value_type> >
class priority_queue {

This says that Compare is some type, and defaults to std::less<T> , for T = the value_type of the underlying container. This compensates for the possibility that you might do something slightly insane like creating a priority_queue of one type, but have the underlying container hold another type (though that's not particularly likely, except by accident).

std::less , in turn, is defined like this:

template <class T> struct less {
    bool operator()(const T& x, const T& y) const;
    // plus a few typedefs for the argument and return types.
};

In short, it's a type defined with only one publicly available operation: an operator() that can be passed two items that it compares, and returns a bool to indicate whether the first is less than the second.

Since that's what std::priority_queue expects to use, whatever you provide must support essentially the same function call-like syntax and semantics (eg, the operator() should take const arguments and should itself be const-qualified).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM