std :: queue 반복


78

반복해야합니다 std::queue. www.cplusplus.com 말한다 :

기본적으로 특정 대기열 클래스에 대해 지정된 컨테이너 클래스가 없으면 표준 컨테이너 클래스 템플릿 deque가 사용됩니다.

그래서 어떻게 든 큐의 기본 deque에 가서 그것을 반복 할 수 있습니까?

답변:


74

반복해야하는 경우 queue대기열 이상의 것이 필요합니다. 표준 컨테이너 어댑터의 요점은 최소한의 인터페이스를 제공하는 것입니다. 반복도해야한다면 데크 (또는 목록)를 대신 사용하지 않는 이유는 무엇입니까?


127
당신이 무슨 말을하는지 알고 있지만, 나는 항상 "대기열 이상의 것"이라는 표현을 싫어했습니다. 열거 형 큐는 여전히 큐입니다. 또한 deque열거 형을 완전히 임의로 지원 하는 방법을 관찰하십시오 . 당신은 그것이 반복 deque만큼 순수해야 queue하고 반복을 지원하지 않아야 한다고 주장 할 수 있습니다 . 그리고 당신이 그것을 반복하고 싶다면 당신은 "더 많은"것을 원합니다. 예 : deque_enumerable. 그러나 그것은 미끄러운 경사이고 내 개인적인 느낌은 queue처음에 열거를 지원 했어야한다는 것입니다.
Roman Starkov

7
@romkyns : "인터페이스보다 더 풍부한 인터페이스를 가진 것이 필요 queue하므로 적절한 인터페이스를 가진 객체를 선택해야합니다 ."라고 다시 표현하면 더 좋을까요? 좋든 싫든, 반복은 queue인터페이스의 일부가 아니므로 반복을 원한다면 다른 것을 선택해야합니다.
CB Bailey

11
내 사용 사례에는 대기열이 필요하지만 디버그 및 로깅 목적으로이를 덤프해야하기 때문입니다. 일반적으로 포스터가 자신이하는 일을 모른다고 가정하는 것은 건설적이지 않습니다.
EML

5
@RomanStarkov- queue내가 생각할 수있는 합리적인 구현에 부담을주지 않고 순방향 반복자를 지원하지만 역방향 반복자를 지원하지 않는 것이 가능 했어야하는 것 같습니다 . CS101 교수님이 그것에 대해 불평했을 것 같네요 ...
TED

4
@EML-정확히 내 필요. 어떻게 든 디버깅 요구 사항은 종종 미친 미치광이에게만 필요한 것으로 무시됩니다
Waslap

37

반복 가능한 컨테이너를 직접 사용하는 것이 선호되는 솔루션이라는 다른 사람들의 의견에 동의하지만 C ++ 표준은 어떤 이유로 든 원하는 경우 자체 솔루션에 대한 충분한 지원을 보장한다는 점을 지적하고 싶습니다.

즉, std::queue보호 된 멤버 에서 상속하고 이를 사용 Container c;하여 기본 컨테이너의 begin () 및 end ()에 액세스 할 수 있습니다 (해당 메서드가 존재하는 경우). 다음은 VS 2010에서 작동 하고 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;
}

4
@Deqing : 맞아; 그러나 기본 컨테이너를 반복하는 것은 우선 순위가 아닙니다.
Alexey Kukanov 2014

1
새 클래스를 재정의하고 deque직접 사용하지 않는 이유는 무엇입니까 ?!
Alexis Wilke

이 참조 @Deqing 질문
피터 K

이 올바른 순서로 반복하므로 @AlexeyKukanov 이것은 우선 순위 큐, 단지 통상 FIFO 큐가 없다
에릭 브렌델

@ErikBrendel, 동일한 기술을 priority_queue와 함께 사용할 수 있는지 묻는 현재 삭제 된 주석에 대한 응답이었습니다.
Alexey Kukanov

14

원래 대기열을 임시 대기열에 저장할 수 있습니다. 그런 다음 임시 대기열에서 일반 팝을 수행하여 원래 대기열을 통과합니다. 예를 들면 다음과 같습니다.

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();
} 

마지막에 tmp_q는 비어 있지만 원래 큐는 변경되지 않습니다.


3
std::queue이하지 않는 것 같습니다 .top()방법
Killzone 아이

1
@KillzoneKid 맞습니다 std::queue. 올바른 방법은.front()
Paul Stelian

4

한 가지 간접 해결책은 std :: deque를 대신 사용하는 것입니다. 큐의 모든 작업을 지원하며을 사용하여 반복 할 수 있습니다 for(auto& x:qu). 반복을 위해 임시 큐 복사본을 사용하는 것보다 훨씬 효율적입니다.


2

반복하려는 대기열의 복사본을 만들고 한 번에 하나씩 항목을 제거하여 이동하면서 인쇄하는 것이 어떻습니까? 반복 할 때 요소로 더 많은 작업을 수행하려면 큐가 잘못된 데이터 구조입니다.


6
어, 아니. 큐를 복사 한 다음 삭제하는 것은 필요한 것보다 훨씬 많은 오버 헤드입니다. 이것이 반복자가 발명 된 이유입니다.
Mac

1
더 간단하게 : 빈 대기열을 만듭니다. 비어있을 때까지 기본 대기열에서 각 항목을 꺼내 원하는대로 처리 한 다음 빈 대기열로 푸시합니다. 완료되면 기본 대기열을 빈 대기열과 동일하게 설정합니다. priority_queue에서도 작동합니다. 주의 : 다른 스레드가 동시에 큐에 액세스하려고하면 스레드로부터 안전하지 않습니다. 원래이 있다면 또한, (통해 생성 된 힙을 할당 malloc/ new)에 확인 free/ delete그것은 또는 당신은 메모리 누수가 있습니다.
Darrel Hoffman

-1 : 실제로 복사하는 매우 작은 대기열에 대해 프레임 속도가 너무 낮아지고 있습니다 (매 프레임마다 복사가 발생하기 때문에 60FPS를 얻지 못합니다. 매우 적은 수의 개체가 있습니다-내 GPU가 300 + FPS를 지원해야하는 것) VSync 비활성화). 복사하지 않고 반복 할 수있는 방법이 필요합니다
Paul Stelian 2018

0

반면 알렉세이 Kukanov의 답변이 더 효율적일 수 있습니다, 당신은 또한 매우 자연스러운 방식으로 큐를 통해, 뒤쪽으로 밀어 다음, 대기열의 전면에서 각 요소를 보여주고으로 반복 할 수있다

#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();
    }
}

산출:

0 1 4 9 16 25 36 49 64 81 

-1

요컨대 : 아니요.

해킹이 있고 벡터를 밑줄 컨테이너로 사용하므로 queue::front유효한 참조를 반환하고 <=까지 반복을 포인터로 변환합니다.queue::back


2
큐로 필요한 모든 메소드를 포함하지만 반복도 지원하는 deque를 직접 사용할 수도 있습니다.
Dewfy

-1

나는 이와 같은 것을 사용합니다. 매우 정교하지는 않지만 작동합니다.

    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. 
    }

q1에서 무언가를 꺼내서 tem에 ​​밀어 넣으면 tem의 첫 번째 요소가되기 때문에 작동합니다. 따라서 결국 tem은 q1의 복제본이됩니다.


이 솔루션은 반복 중에 큐를 수정하기 때문에 매우 문제가 있습니다. 다중 스레드 프로그램에서 사용하거나 중간에서 반복을 중지하는 경우 어떻게 될지 상상해보십시오.
jackhab

@ jackhab 감사합니다. 당신이 옳습니다. 문제가 될 수 있습니다. 그러나 세마포어 또는 뮤텍스를 사용하여 해당 문제를 극복 할 수 있습니다 (IPC 및 pthread의 운영 체제 할당에서 수행하는 것처럼).
shamiul97

-2

큐를 반복해야하는 경우 큐는 필요한 컨테이너가 아닙니다.
대기열을 선택한 이유는 무엇입니까?
반복 할 수있는 컨테이너를 가져가는 것이 어떻습니까?


1. 대기열을 선택하면 컨테이너를 '대기열'인터페이스로 감싸고 싶다고 말합니다.-전면-후면-푸시-팝-...

반복하려는 경우 대기열에 잘못된 인터페이스가 있습니다. 대기열은 원래 컨테이너의 제한된 하위 집합을 제공하는 어댑터입니다.

2. 큐의 정의는 FIFO이며 정의에 따라 FIFO는 반복 할 수 없습니다.


36
나는 OP는 아니지만 누군가 궁금한 경우를 대비하여 내 대답은 다음과 같습니다. 1) 대기열을 원하기 때문에 대기열을 선택했습니다. 한쪽 끝은 대기열에 넣고 다른 쪽 끝은 대기열에서 빼고 싶습니다. 이것은 합리적인 선택이 아닙니까? 2) "대기열"이 열거 할 수 없는지, 대신 사용할 구조가 명확하지 않습니다. 대신 사용할 용기를 설명했다면 답변이 더 도움이 될 것입니다.
Roman Starkov

-2

std::queue컨테이너 어댑터이며 사용되는 컨테이너를 지정할 수 있습니다 (기본값은를 사용함 deque). 어댑터에서 그 이상의 기능이 필요한 경우 하나 deque또는 다른 컨테이너를 직접 사용하십시오.


4
귀하의 답변은 정확하지만, 그럴 필요가 전혀 없었습니다.이 2 년 된 질문에는 이미 두 개의 답변이 정확히 똑같기 때문입니다 (그 중 하나가 허용 된 답변입니다).
Christian Rau 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.