如何迭代priority_queue?

发布于 2024-10-08 05:21:07 字数 141 浏览 0 评论 0原文

我可以使用迭代器(如 vector)遍历 C++ 中的标准 priority_queue 或标准 queue 吗?我不想使用 pop,因为它会导致我的队列出队。

感谢您的帮助

Can I traverse a standard priority_queue or standard queue in c++ with an iterator (like a vector)? I don't want to use pop because it cause my queue to be dequeued.

Thanks for any help

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

倥絔 2024-10-15 05:21:08

队列有目的地提供有限的接口,其中排除了迭代。但既然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;
}

对于优先级队列的类似答案:不,你不能。但在本例中,默认使用向量。在这两种情况下,您都无法访问底层容器来迭代它们。请参阅此问题以进一步阅读。

A queue purposefully provides a limited interface, which excludes iteration. But since a queue uses a deque as the underlying container, why not use a deque directly?

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

Similar answer for a priority queue: no, you cannot. In this case though, a vector is used by default. In neither case can you access the underlying container to iterate over them. See this question for further reading.

败给现实 2024-10-15 05:21:08
#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;
}
#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;
}
栖迟 2024-10-15 05:21:08

是的,复制priority_queue并对其进行迭代。

Yes, make a copy of the priority_queue and iterate over that.

鲜肉鲜肉永远不皱 2024-10-15 05:21:08

这是不可能的。您必须使用不同的容器,可能是 deque 将为您提供最好的服务。

This is not possible. You would have to use a different container, probably a deque would serve you best.

不醒的梦 2024-10-15 05:21:08

我在偶然发现你的问题后发现了这一点。有一种非常简单的方法可以通过编写继承自 std::priority_queue 的实现来实现此目的。全部是14行。

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

I found this after stumbling across your question. There is a very simple way of doing this by writing an implementation inheriting from std::priority_queue. It is all of 14 lines.

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

愁杀 2024-10-15 05:21:08

队列与向量完全不同,并且用于不同的目的。优先级队列只是排序的双端队列,无法直接访问后面。但是,如果您迫切希望对任何方法执行此操作,您可以做的就是弹出顶部/前面的元素,将其添加到列表/数组/向量中,然后将该元素推回到队列中 for(size_t i = 0; q.size();我参加了 Java 数据结构课程,这是考试问题的答案。而且这是我能想到的唯一方法。

Queues are totally different from vectors and are used for different purposes. Priority queues are simply sorted deques with no direct access to the back. However, if you desperately want to do this for whatever method, what you can do is pop off the top/front element, add it to a list/array/vector, and then push the element back into your queue for(size_t i = 0; i < q.size(); i++). I took a class in java data structures, and this was the answer to an exam question. Plus it is the only method i can think of.

白芷 2024-10-15 05:21:08

其中许多答案依赖于编码/使用许多 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 结构的容器类时。

Many of these answers rely on coding/using many of C++ arcane features. That's ok, fun and funds expensive programmers. A direct solution that is quick, cheap to program but more expensive to run, is:

// 
// 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;

By the way, it seems perfectly non-sensible to NOT provide an iterator for a priority_queue, especially when it is a container class for a or structure.

蒗幽 2024-10-15 05:21:08

大多数现有答案要么建议使用不同的数据结构,要么执行一系列 O(log n) 操作(n 是优先级队列的大小)。有些人甚至建议复制该结构。

该操作可以相对于元素数量以线性时间执行,前提是:

  • 底层容器是向量,并且
  • 不需要按排序顺序遍历元素。

如果满足这些条件,则可以使用以下代码:

#include <iostream>
#include <queue>

int main()
{
    using T = int;
    std::priority_queue<T, std::vector<T>, std::less<T>> q;
    
    q.emplace(1); q.emplace(16); q.emplace(5); q.emplace(42); q.emplace(3);
    
    const T* base = &q.top(); // root of the binary heap
    for(size_t i = 0; i<q.size(); i++)
        std::cout << *(base+i)<<" ";
    std::cout << std::endl; // outputs "42 16 5 1 3"

    return 0;
}

这种方法的优点是不更改所使用的数据结构:如果二进制堆适合您的应用程序,则使用多重集是没有意义的。而且它结构紧凑,实现起来很简单,不会改变原始对象,也不需要额外的内存。最后,它的运行时间为O(n),而不是常见的O(n log n)

Most existing answers either suggest using a different data structure or performing a sequence of O(log n) operations (n being the size of the priority queue). Some even advise to make a copy of the structure.

The operation can be performed in linear time with respect to the number of elements, provided that :

  • the underlying container is a vector, and
  • it is not necessary to go through the elements in sorted order.

If these conditions are met, the following code can be used :

#include <iostream>
#include <queue>

int main()
{
    using T = int;
    std::priority_queue<T, std::vector<T>, std::less<T>> q;
    
    q.emplace(1); q.emplace(16); q.emplace(5); q.emplace(42); q.emplace(3);
    
    const T* base = &q.top(); // root of the binary heap
    for(size_t i = 0; i<q.size(); i++)
        std::cout << *(base+i)<<" ";
    std::cout << std::endl; // outputs "42 16 5 1 3"

    return 0;
}

This approach has the advantage of not changing the data structure used : if a binary heap is suited for your application, there is no point in using a multiset. Also it is compact, trivial to implement, does not change the original object and does not require additional memory. Finally, it runs in O(n) time instead of the commonly seen O(n log n).

另类 2024-10-15 05:21:08

C++priority_queue 不提供可用于迭代它的 .begin() 指针(如向量那样)。

如果您想迭代优先级队列以搜索它是否包含值,那么可以创建一个包装器优先级队列并使用哈希集来跟踪队列中的内容。

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_;
};

C++ priority_queue does not offer a .begin() pointer (like vector would do) that you can use to iterate over it.

If you want to iterate over the priority queue to search for whether it contains a value then maybe create a wrapper priority queue and use a hash set to keep track of what you have in the queue.

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_;
};
[浮城] 2024-10-15 05:21:08

出于基本目的, std::multiset将为您提供类似的属性,但具有迭代能力:

  • 项目已排序,可以定义自定义 Less
  • 键可以出现多次
  • 快速访问和删除第一个项目

For basic purposes, a std::multiset will give you similar properties but with the ability to iterate:

  • Items sorted, custom Less can be defined
  • Keys can occur multiple times
  • Quick to access and remove first item
二货你真萌 2024-10-15 05:21:08

制作副本并迭代 - 由 @lie-ryan 建议

#include <iostream>
#include <queue>

using namespace std;
void make_copy(priority_queue<int, vector<int>> pq, vector<int> &arr)
{
    arr = {}; // if it was not empty , make it :)
    while (!pq.empty())
    {
        arr.push_back(pq.top());
        pq.pop();
    }
}
int main()
{
    priority_queue<int, vector<int>> q;
    q.push(1);
    q.push(2);
    q.push(3);
    vector<int> arr;
    make_copy(q, arr); // this will copy all elements of q to arr :)
    for (auto &x : arr)
    {
        cout << x << " ";
    }
}

Making a copy and iterating over that - suggested by @lie-ryan

#include <iostream>
#include <queue>

using namespace std;
void make_copy(priority_queue<int, vector<int>> pq, vector<int> &arr)
{
    arr = {}; // if it was not empty , make it :)
    while (!pq.empty())
    {
        arr.push_back(pq.top());
        pq.pop();
    }
}
int main()
{
    priority_queue<int, vector<int>> q;
    q.push(1);
    q.push(2);
    q.push(3);
    vector<int> arr;
    make_copy(q, arr); // this will copy all elements of q to arr :)
    for (auto &x : arr)
    {
        cout << x << " ";
    }
}
落花随流水 2024-10-15 05:21:08

我自己也有同样的疑问。我发现要了解优先级队列底层的数据结构非常困难,甚至可能是不可能的。就我而言,这是一个对象向量。

但是,我最终使用了标准模板库堆。它几乎和优先级队列一样简单(它需要两条指令来推送和弹出,而 pq 则需要 1 条指令),否则行为似乎是相同的

如果我不修改它,我可以获取底层数据结构。

I had the same question myself. I found it was very difficult, maybe impossible, to get to the data structure underlying the priority queue. In my case this was a vector of objects.

However, I ended up using a standard template library heap. It is almost as easy as a priority queue (it takes two instructions to push and pop, vs. 1 for the pq), otherwise the behavior seems to be identical
and
I can get at the underlying data structure if I don't modify it.

情场扛把子 2024-10-15 05:21:08

如果你想以复杂度(logN)的有序方式推送项目。但如果还想按升序迭代元素,您可以使用 set
集合通常被实现为二叉搜索树。

集合是可迭代的(开始、结束、rbegin、rend 等)

If you want to push items in an ordered manner with complexity (logN). But would like to iterate over the elements as well in increasing order, you can use set<int>.
Sets are typically implemented as binary search trees.

Sets are iterable (begin, end, rbegin, rend etc)

世界如花海般美丽 2024-10-15 05:21:08

我遇到了同样的问题,我想迭代优先级队列而不出队(因此破坏了我的队列)。我通过将priority_queue指针重新转换为指向向量的指针(因为我的priority_queue使用向量作为其容器)使其对我有用。它是这样的:

class PriorityQueue {
  private:
    class Element {
    int x; 
    //Other fields
    ...
    ..
    //Comparator function
    bool operator()(const Element* e1, const Element* e2) const {
        // Smallest deadline value has highest priority.
        return e1->x > e2->x;
    }
    };
    // Lock to make sure no other thread/function is modifying the queue
    // Ofcourse we can do our operation w/o lock. if we are sure what is happening in other functions
    pthread_mutex_t lock;   
    std::priority_queue<Element*, std::vector<Element*>, Element> pq;

  public:
    PriorityQueue();
    ~PriorityQueue();
    //print the all the elements of the queue
    void print_queue_elements() {
        std::vector<PriorityQueue::Element*> *queue_vector;
        //Acquire the lock
        pthread_mutex_lock(&lock);
        //recast the priority queue to vector
        queue_vector = reinterpret_cast<std::vector<PriorityQueue::Element*> *>(&pq);
        for(std::vector<PriorityQueue::Element*>::iterator it = (*queue_vector).begin(); it != (*queue_vector).end(); it++) {
            //Assuming Element class has string function
            printf("My Element %s", (*it)->string);
            //other processing with queue elements
        }
        //Release the lock
        pthread_mutex_unlock(&lock);    

    }
    //other functions possibly modifying the priority queue
    ...
    ..
    .
 };

现在由于我使用reinterpret_cast,人们可以争论类型安全。但在这种情况下,我确信所有其他功能都可以访问/更改队列(所有这些功能都是安全的)..而且我觉得这是比将整个队列的内容复制到其他容器更好的方法。

我实际上期望static_cast能够工作..因为priority_queue是容器上的适配器(在我们的例子中是向量),但事实并非如此,我不得不使用reinterpret_cast

I had the same problem, where I wanted to iterate over a priority queue without dequeuing (hence destroying my queue). I made it work for me by recasting my priority_queue pointer to a pointer to a vector (as my priority_queue uses vector as its container). Here is how it looks like:

class PriorityQueue {
  private:
    class Element {
    int x; 
    //Other fields
    ...
    ..
    //Comparator function
    bool operator()(const Element* e1, const Element* e2) const {
        // Smallest deadline value has highest priority.
        return e1->x > e2->x;
    }
    };
    // Lock to make sure no other thread/function is modifying the queue
    // Ofcourse we can do our operation w/o lock. if we are sure what is happening in other functions
    pthread_mutex_t lock;   
    std::priority_queue<Element*, std::vector<Element*>, Element> pq;

  public:
    PriorityQueue();
    ~PriorityQueue();
    //print the all the elements of the queue
    void print_queue_elements() {
        std::vector<PriorityQueue::Element*> *queue_vector;
        //Acquire the lock
        pthread_mutex_lock(&lock);
        //recast the priority queue to vector
        queue_vector = reinterpret_cast<std::vector<PriorityQueue::Element*> *>(&pq);
        for(std::vector<PriorityQueue::Element*>::iterator it = (*queue_vector).begin(); it != (*queue_vector).end(); it++) {
            //Assuming Element class has string function
            printf("My Element %s", (*it)->string);
            //other processing with queue elements
        }
        //Release the lock
        pthread_mutex_unlock(&lock);    

    }
    //other functions possibly modifying the priority queue
    ...
    ..
    .
 };

Now since I am using reinterpret_cast, people can argue about type-safety. But in this case I am sure about all other functions accessing/changing the queue (all of which are safe).. and I feel this is a much better way than copying the content of whole queue to some other container.

I was actually expecting static_cast to work.. as priority_queue is adaptor over container (vector in our case), but it doesnt and I had to use reinterpret_cast.

撩人痒 2024-10-15 05:21:07

priority_queue 不允许迭代所有成员,大概是因为很容易使队列的优先级排序无效(通过修改您遍历的元素),或者这可能是“不是我的工作”理由。

官方的解决方法是使用 vector 并使用 make_heappush_heappop_heap 自行管理优先级代码>.在 @Richard 的回答中,另一个解决方法是使用从 priority_queue 派生的类并访问具有 protected 可见性的底层存储。

priority_queue doesn't allow iteration through all the members, presumably because it would be too easy in invalidate the priority ordering of the queue (by modifying the elements you traverse) or maybe it's a "not my job" rationale.

The official work-around is to use a vector instead and manage the priority-ness yourself with make_heap, push_heap and pop_heap. Another work-around, in @Richard's answer, is to use a class derived from priority_queue and access the underlying storage which has protected visibility.

虐人心 2024-10-15 05:21:07

你可以这样做 - 砰!请注意,项目在队列中时不一定按“排序”顺序,至少对于容器的直接迭代而言是如此。

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

You can do it like this - bam! Notice that items are not necessarily in "sorted" order while they are in the queue, at least with regards to a straight-forward iteration of the container.

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文