队列迭代

我需要遍历 std::queue。 Www.cplusplus.com 表示:

默认情况下,如果没有为特定队列类指定容器类,则使用标准容器类模板 deque。

那么我是否可以找到队列的底层 deque 并对它进行迭代呢?

193927 次浏览

If you need to iterate over a queue then you need something more than a queue. The point of the standard container adapters is to provide a minimal interface. If you need to do iteration as well, why not just use a deque (or list) instead?

In short: No.

There is a hack, use vector as underlaid container, so queue::front will return valid reference, convert it to pointer an iterate until <= queue::back

If you need to iterate a queue ... queue isn't the container you need.
Why did you pick a queue?
Why don't you take a container that you can iterate over?


1.if you pick a queue then you say you want to wrap a container into a 'queue' interface: - front - back - push - pop - ...

if you also want to iterate, a queue has an incorrect interface. A queue is an adaptor that provides a restricted subset of the original container

2.The definition of a queue is a FIFO and by definition a FIFO is not iterable

While I agree with others that direct use of an iterable container is a preferred solution, I want to point out that the C++ standard guarantees enough support for a do-it-yourself solution in case you want it for whatever reason.

Namely, you can inherit from std::queue and use its protected member Container c; to access begin() and end() of the underlying container (provided that such methods exist there). Here is an example that works in VS 2010 and tested with ideone:

#include <queue>
#include <deque>
#include <iostream>


template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;


iterator begin() { return this->c.begin(); }
iterator end() { return this->c.end(); }
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};


int main() {
iterable_queue<int> int_queue;
for(int i=0; i<10; ++i)
int_queue.push(i);
for(auto it=int_queue.begin(); it!=int_queue.end();++it)
std::cout << *it << "\n";
return 0;
}

std::queue is a container adaptor, and you can specify the container used (it defaults to use a deque). If you need functionality beyond that in the adaptor then just use a deque or another container directly.

Why not just make a copy of the queue that you want to iterate over, and remove items one at a time, printing them as you go? If you want to do more with the elements as you iterate, then a queue is the wrong data structure.

you can save the original queue to a temporary queue. Then you simply do your normal pop on the temporary queue to go through the original one, for example:

queue tmp_q = original_q; //copy the original queue to the temporary queue


while (!tmp_q.empty())
{
q_element = tmp_q.front();
std::cout << q_element <<"\n";
tmp_q.pop();
}

At the end, the tmp_q will be empty but the original queue is untouched.

I use something like this. Not very sophisticated but should work.

    queue<int> tem;


while(!q1.empty()) // q1 is your initial queue.
{
int u = q1.front();


// do what you need to do with this value.


q1.pop();
tem.push(u);
}




while(!tem.empty())
{
int u = tem.front();
tem.pop();
q1.push(u); // putting it back in our original queue.
}

It will work because when you pop something from q1, and push it into tem, it becomes the first element of tem. So, in the end tem becomes a replica of q1.

while Alexey Kukanov's answer may be more efficient, you can also iterate through a queue in a very natural manner, by popping each element from the front of the queue, then pushing it to the back:

#include <iostream>
#include <queue>


using namespace std;


int main() {
//populate queue
queue<int> q;
for (int i = 0; i < 10; ++i) q.push(i);


// iterate through queue
for (size_t i = 0; i < q.size(); ++i) {
int elem = std::move(q.front());
q.pop();
elem *= elem;
q.push(std::move(elem));
}


//print queue
while (!q.empty()) {
cout << q.front() << ' ';
q.pop();
}
}

output:

0 1 4 9 16 25 36 49 64 81

One indirect solution can be to use std::deque instead. It supports all operations of queue and you can iterate over it just by using for(auto& x:qu). It's much more efficient than using a temporary copy of queue for iteration.