C++ 如何制作STL';s优先级队列固定大小

C++ 如何制作STL';s优先级队列固定大小,c++,stl,std,C++,Stl,Std,我正在创建一个简单的游戏,我使用std::priority\u queue向小队发出命令(每个小队都有priority\u queue) 机器人每隔20秒分析一次情况,并将命令发送到优先级队列 如何使优先级\u队列固定大小,例如,将大小设置为10?所需的效果是,当达到最大值时,如果我向队列中添加2个新命令,则具有最低优先级的2个现有命令将自动删除。将其包装到另一个类中,该类将为您执行此操作。该标准本身不提供此类功能。这很狡猾,但您应该能够覆盖std::priority_queue的功能来完成您需

我正在创建一个简单的游戏,我使用
std::priority\u queue
小队发出命令(每个小队都有
priority\u queue

机器人每隔20秒分析一次情况,并将命令发送到
优先级队列


如何使
优先级\u队列
固定大小,例如,将大小设置为10?所需的效果是,当达到最大值时,如果我向队列中添加2个新命令,则具有最低优先级的2个现有命令将自动删除。

将其包装到另一个类中,该类将为您执行此操作。该标准本身不提供此类功能。

这很狡猾,但您应该能够覆盖
std::priority_queue
的功能来完成您需要的操作。这似乎在我做的一些测试中起作用:

template<typename T>
class fixed_priority_queue : public std::priority_queue<T> 
{
  public:
    fixed_priority_queue(unsigned int size) : fixed_size(size) {}
    void push(const T& x) 
    { 
      // If we've reached capacity, find the FIRST smallest object and replace
      // it if 'x' is larger
      if(this->size() == fixed_size)
      {
        // 'c' is the container used by priority_queue and is a protected member.
        auto beg = c.begin(); auto end = c.end();
        auto min = std::min_element(beg, end);
        if(x > *min)
        {
            *min = x;
            // Re-make the heap, since we may have just invalidated it.
            std::make_heap(beg, end);
        }
      }
      // Otherwise just push the new item.
      else          
      {
        priority_queue::push(x);
      }
    }
  private:
    fixed_priority_queue() {} // Construct with size only.
    const unsigned int fixed_size;
    // Prevent heap allocation
    void * operator new   (size_t);
    void * operator new[] (size_t);
    void   operator delete   (void *);
    void   operator delete[] (void*);
};
这里有什么不好

  • 您无法在堆上安全地创建这些队列,因此大队列可能是不可能的。20左右,正如您所提到的,不管怎样,在堆栈上都应该可以(取决于对象)。我可能会避免排大队,因为
  • 我不确定这里的演出是否成功<代码>优先级队列调用底层容器上的
    生成堆
    (默认情况下为std::vector)。我不确定它通常多久调用一次,但如果队列已满,我们会经常调用它。我想它也可以在
    priority\u queue::push()中调用
  • 可能是一堆其他东西,所以我欢迎读者提供所有建设性的反馈和编辑:)
希望这是有用的,如果不是最有趣的。

适用于这个问题

使用最大堆

假设您有一个N元素堆(实现为数组),其中 包含迄今为止看到的N个最小元素

当一个元素进入时,你对照最大值(O(1)时间)进行检查,并且 如果更大,则拒绝


前面几条评论提到的迭代是不必要的。

一个想法是创建一个最小优先级队列,并使用size()方法仅将优先级队列填充到所需的级别。大概是这样的:

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

struct Compare {
    // priority queue is max heap by default, use compare
    // to make it minheap
    bool operator() (const int& a, const int& b) {
        return a>b;
    }
};

typedef priority_queue<int, vector<int>, Compare> pqSize;

void priorityQueueFixedSize(pqSize& pq, int size, vector<int>& vec) {
    for (int i=0;i<vec.size();i++) {
        if (pq.size() < size) {
            pq.push(vec[i]);
        } else {
            if (vec[i] > pq.top()) {
                pq.pop();
                pq.push(vec[i]);
            }
        }
    }
}

void printPQ(pqSize& pq) {
    while (!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;
}

int main() {
    vector<int> vec(20,0);
    for (int i=0;i<vec.size();i++) {
        vec[i] = i;
    }
    pqSize pq;
    priorityQueueFixedSize(pq,10, vec);
    printPQ(pq);
}
#包括
#包括
#包括
使用名称空间std;
结构比较{
//优先级队列默认为最大堆,使用比较
//把它弄碎
布尔运算符(){
返回a>b;
}
};
typedef优先级\u队列大小;
void priorityQueueFixedSize(pqSize和pq、int size、vector和vec){
对于(int i=0;i pq.top()){
pq.pop();
电能质量推送(矢量[i]);
}
}
}
}
无效打印pq(pq尺寸和pq){
而(!pq.empty()){

cout标准提供了一组基本堆操作:

make\u堆
排序堆
推送堆
堆
我们可以将其封装在一个简单的类中,该类的数据成员是
命令[10]
std::array
,或者以较低级别的方式使用上述四个函数


我个人建议不要将其包装在函数中,因为您可能希望采用ECS模式并对命令应用更多可能的操作,而不仅仅是作为优先级队列。我们知道,如果使用优先级队列,可能会出现不必要的复制或移动。

一个有点棘手的解决方案不是使用std::priotity_队列,而是使用std::array wi大小N+1,其中只有前N个元素是一个真正的队列。您不使用最低优先级替换元素,而是使用新命令覆盖
queue.back()
。然后
pop_队列(q.begin(),q.end())
将新命令添加到队列中

这是我的代码,它是有效的:

int main() {
    std::array<int, 10> queue;
    queue.fill(500);
 
    for(int i = 0; i < 1000; i++)
    {
        queue.back() = rand() % 1000;
        pop_heap(queue.begin(), queue.end(), std::greater<int>());
        //print_queue(queue);
        assert(is_heap(queue.begin(), queue.end()-1, std::greater<int>()));
    }
}
intmain(){
std::数组队列;
排队。填写(500);
对于(int i=0;i<1000;i++)
{
queue.back()=rand()%1000;
pop_堆(queue.begin()、queue.end()、std::greater());
//打印队列(队列);
断言(是堆(queue.begin(),queue.end()-1,std::greater());
}
}

另一件事是,您的规范是否是您真正想要的。不要忘记在优先级中添加年龄。如果您不这样做,那么经过一百万次迭代后,您将有10个元素,具有最高优先级。无论何时将它们添加到队列中。

这是一个新的元素。幸运的是,我从来没有这样做过。我怀疑@DeadMG具有相同的优先级非常明显的解决方案-您必须编写一些代码来完成这项工作,锁定队列并对其进行迭代:(这是一种肮脏的黑客行为,可以访问
优先级队列的底层容器
(示例使用
堆栈,但原理相同)。不过,可能还有更好的解决方案。
priority\u queue
在底层容器中实现了一个二进制排序堆。它不是为了迭代而设计的,而是为了使顶部元素最大,并在日志时间内执行
push
pop
。我认为您应该在这里使用私有继承。您知道
fixed_priority_queue
不是一个
std::priority_queue
?因此,使用私有继承或组合。这应该是一种更高的方法,这是标准的方法,可能是最有效的方法。有关正确的解决方案,请参阅下面的于志昌评论
int main() {
    std::array<int, 10> queue;
    queue.fill(500);
 
    for(int i = 0; i < 1000; i++)
    {
        queue.back() = rand() % 1000;
        pop_heap(queue.begin(), queue.end(), std::greater<int>());
        //print_queue(queue);
        assert(is_heap(queue.begin(), queue.end()-1, std::greater<int>()));
    }
}