6

Is there a way to iterate over a priority queue in c++ ? My understanding is that they are more or less immutable and the only manipulation of the container is to the top element. I would like to be able to print out the contents of a priority queue but am unsure of how to even approach the problem.

Keith
  • 123
  • 4
  • 10
  • 2
    A quick and dirty way is to copy and dequeue, I suppose. – theoden8 Jan 27 '17 at 23:00
  • Not sure if anything new in C++ has changed the [advice in this question](http://stackoverflow.com/questions/4484767/how-to-iterate-over-a-priority-queue). – tadman Jan 27 '17 at 23:02
  • Are you asking about std::priority_queue? –  Jan 27 '17 at 23:04
  • @Neil Butterworth yes – Keith Jan 27 '17 at 23:05
  • @Keith Then no, not without copying or modifying the queue. I've always thought that queues and stacks should give read-access to the underlying container, but they don't. –  Jan 27 '17 at 23:10
  • @NeilButterworth Actually `std::priority_queue` does give access to the underlying container through inheritance, even though it's kindly discouraged. – skypjack Jan 27 '17 at 23:18
  • @sky Oh, I forgot that it was protected :-( It shouldn't be, IMHO. –  Jan 27 '17 at 23:21
  • @NeilButterworth I've just found that, don't worry. That's why I like to try to answer on SO: I learn a lot!! ;-) – skypjack Jan 27 '17 at 23:23
  • Thanks for all the input. That gives me a direction to work in. – Keith Jan 27 '17 at 23:25

2 Answers2

6

The underlying container is a protected data member named c (see here for further details). Therefore you can always inherit from a std::priority_queue and export a couple of iterators over that container (if available).
As a minimal, working example:

#include<queue>
#include<iostream>

struct MyPriorityQueue: std::priority_queue<int> {
    auto begin() const { return c.begin(); }
    auto end() const { return c.end(); }
};

int main() {
    MyPriorityQueue pq;
    pq.push(0);
    pq.push(1);
    for(auto &v: pq) {
        std::cout << v << std::endl;
    }
}

Note: inheriting from data structures in the std:: namespace is usually discouraged.
That being said, it works at least.


The code above works in C++14.
Below a slightly modified version that works also in C++11 as requested in the comments:

#include<queue>
#include<iostream>

struct MyPriorityQueue: std::priority_queue<int> {
    decltype(c.begin()) begin() const { return c.begin(); }
    decltype(c.end()) end() const { return c.end(); }
};

int main() {
    MyPriorityQueue pq;
    pq.push(0);
    pq.push(1);
    for(auto &v: pq) {
        std::cout << v << std::endl;
    }
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • auto begin() gives error C3551: expected a trailing return type. At least when compiling with VS2013. – Laszlo Jan 28 '17 at 00:33
  • @Laszlo It's C++14. Put there the right type or a `decltype` to have it working in C++11. I'm updating the answer anyway. – skypjack Jan 28 '17 at 07:45
  • `error: could not convert ‘((const MyPriorityQueue*)this)->MyPriorityQueue::.std::priority_queue::c.std::vector<_Tp, _Alloc>::begin >()’ from ‘std::vector >::const_iterator {aka __gnu_cxx::__normal_iterator > >}’ to ‘std::vector >::iterator {aka __gnu_cxx::__normal_iterator > >}’ decltype(c.begin()) begin() const { return c.begin(); }` – Kenenbek Arzymatov Nov 29 '17 at 17:05
3

Based on @skypjack's answer, here is a templated version:

#include<queue>
#include<iostream>

template<class T, class C = vector<T>, class P = less<typename C::value_type> >
struct MyPriorityQueue :
   std::priority_queue<T,C,P> {
   typename C::iterator begin() { return std::priority_queue<T, C, P>::c.begin(); }
   typename C::iterator end() { return std::priority_queue<T, C, P>::c.end(); }
};

int main() {
   MyPriorityQueue<int> pq;
   pq.push(0);
   pq.push(1);
   for (auto &v : pq) {
      std::cout << v << std::endl;
   }
}
Laszlo
  • 769
  • 9
  • 19
  • Unable to use it with `typedef`, For example: `typedef MyPriorityQueue, Cmp> customq_type;` `customq_type customq(param);` Gets the following: `error: no matching constructor for initialization of customq_type`. Please help. – TJain Mar 02 '18 at 19:21
  • 2
    This is because the constructors were not inherited. `using priority_queue::priority_queue`, we should be able to inherit the constructors. – TJain Mar 02 '18 at 21:38