web-dev-qa-db-ja.com

priority_queueを反復処理する方法は?

イテレータ(queueなど)を使用してc ++の標準priority_queueまたは標準vectorをトラバースできますか? popを使用したくないのは、キューがデキューされるためです。

助けてくれてありがとう

58
mina70

priority_queueはすべてのメンバーの反復を許可していません。おそらく、キューの優先順位を無効にするのは簡単すぎるため(トラバースする要素を変更すること)、または「自分の仕事ではない」理由です。

公式の回避策は、代わりにvectorを使用し、make_heapPush_heap、およびpop_heapで優先度を管理することです。 @Richardの答えでの別の回避策は、priority_queueから派生したクラスを使用し、protected可視性を持つ基盤ストレージにアクセスすることです。

19
xan

このようにできます-バム!少なくともコンテナの単純な繰り返しに関しては、アイテムがキューにある間は必ずしも「ソートされた」順序ではないことに注意してください。

#include <queue>
#include <cstdlib>
#include <iostream>
using namespace std;

template <class T, class S, class C>
S& Container(priority_queue<T, S, C>& q) {
    struct HackedQueue : private priority_queue<T, S, C> {
        static S& Container(priority_queue<T, S, C>& q) {
            return q.*&HackedQueue::c;
        }
    };
    return HackedQueue::Container(q);
}

int main()
{
    priority_queue<int> pq;
    vector<int> &tasks = Container(pq);

    cout<<"Putting numbers into the queue"<<endl;
    for(int i=0;i<20;i++){
        int temp=Rand();
        cout<<temp<<endl;
        pq.Push(temp);
    }

    cout<<endl<<"Reading numbers in the queue"<<endl;
    for(vector<int>::iterator i=tasks.begin();i!=tasks.end();i++)
        cout<<*i<<endl;

    cout<<endl<<"Taking numbers out of the queue"<<endl;
    while(!pq.empty()){
        int temp=pq.top();
        pq.pop();
        cout<<temp<<endl;
    }

    return 0;
}
12
Richard

queueは、意図的に制限されたインターフェイスを提供し、反復を除外します。しかし、queueは基になるコンテナとしてdequeを使用するので、なぜdequeを直接使用しないのですか?

#include <iostream>
#include <queue>
using namespace std;

int main() {
  deque<int> q;
  q.Push_back(1);
  q.Push_back(2);
  q.Push_back(3);
  for(deque<int>::iterator it = q.begin(); it != q.end(); ++it)
    cout << *it << endl;
}

優先キューの同様の答え:いいえ、できません。ただし、この場合、vectorがデフォルトで使用されます。どちらの場合も、基礎となるコンテナにアクセスしてそれらを反復処理することはできません。詳細については、 この質問 を参照してください。

10
marcog

はい、priority_queueのコピーを作成し、それを繰り返します。

4
Lie Ryan
#include <queue>
#include <iostream>

int main() {
    std::priority_queue<int> pq;

    pq.Push_back(1);
    pq.Push_back(2);
    pq.Push_back(3);

    std::priority_queue<int> temp = pq;

    while (!temp.empty()) {
        std::cout << temp.top() << std::endl;
        temp.pop();
    }

    return 0;
}
3
Snooze

これは不可能です。別のコンテナを使用する必要があります。おそらく、 deque が最適です。

3
Björn Pollex

あなたの質問につまずいた後に私はこれを見つけました。 std :: priority_queueを継承する実装を記述することにより、これを行う非常に簡単な方法があります。 14行すべてです。

http://www.linuxtopia.org/online_books/programming_books/c++_practical_programming/c++_practical_programming_189.html

3
Jonathan Henson

キューはベクターとはまったく異なり、さまざまな目的に使用されます。優先キューは単純に並べ替えられた両端キューであり、バックに直接アクセスすることはできません。ただし、何らかの方法で必死にこれを行いたい場合は、トップ/フロント要素からポップし、リスト/配列/ベクトルに追加してから、要素を(size_t i = 0; i <q.size(); i ++)。私はJavaデータ構造でクラスを取りました。これは試験問題に対する答えでした。さらに、それは私が考えることができる唯一の方法です。

2
sj755

これらの回答の多くは、C++の多くの難解な機能のコーディング/使用に依存しています。それは大丈夫、楽しく、高価なプログラマーに資金を提供します。迅速で、プログラムは安価ですが、実行はより高価な直接的なソリューションは次のとおりです。

// 
// Only use this routine when developing code, NOT for production use!!
//
// Note. _pq is in private for a class that uses the priority queue
// and listQueue is a public method in that same class.
//
void listQueue() {

    // allocate pointer to a NEW container
    priority_queue<int>* new_pq = new  priority_queue<int>;

    while (!_pq->empty()) {

        int el = _pq->top();

        cout << "(" << el << ")" << endl;

        new_pq->Push(el);

        _pq->pop();

    } // end while;

    // remove container storage
    delete(_pq);

    // viola, new container same as the old
    _pq = new_pq;

} // end of listQueue;

ところで、priority_queueのイテレータを指定しないことは、特にそれがor構造のコンテナクラスである場合、まったく意味がないようです。

2
JackCColeman

C++ priority_queueは、それを反復するために使用できる.begin()ポインター(vectorが提供するような)を提供しません。

優先度キューを反復処理して値が含まれているかどうかを検索する場合は、ラッパー優先度キューを作成し、ハッシュセットを使用してキューにあるものを追跡することができます。

class MyPriorityQueue {

   MyPriorityQueue() {}

   void Push(int item) {
     if (!contains(item)){
       pq_.Push(item);
       set_.emplace(item);
     }
   }
   void pop() {
     if (!empty()) {
       int top = pq_.top();
       set_.erase(top);
       pq_.pop();
     }
   }
   int top() { return pq_.top(); }
   bool contains(int item) { return set_.find(item) != set_.end(); }
   bool empty() const { return set_.empty(); }

 private:
   std::priority_queue<int> pq_;
   std::unordered_set<int> set_;
};
0
mario

私自身も同じ質問をしました。優先度キューの基礎となるデータ構造に到達することは非常に困難で、おそらく不可能であることがわかりました。私の場合、これはオブジェクトのベクトルでした。

ただし、標準テンプレートライブラリヒープを使用することになりました。優先度キューとほぼ同じくらい簡単です(プッシュとポップに2つの命令がかかりますが、pqの場合は1) 。

0
David E.

基本的な目的のために、 std::multiset は同様のプロパティを提供しますが、反復する機能があります。

  • ソートされたアイテム、カスタムLessを定義可能
  • キーは複数回発生する可能性があります
  • 最初のアイテムにすばやくアクセスして削除する
0
AndiDog