我可以通过清除其底层容器来清除priority_queue

May I clear a priority_queue by clearing its underlying container?

本文关键字:清除 priority queue 可以通过      更新时间:2023-10-16

以下代码继承了std::p riority_queue,并提供了调用内部std::vector clear()clear()

#include<iostream>
#include<queue>
using namespace std;
template<class type>
struct mypq :public priority_queue<type> {
    void clear(){
        this->c.clear();
    }
};
mypq<int>pq;
int main() {
    for(int i=0;i<10;++i)
        pq.push(i);
    pq.clear();
    for(int j=-5;j<0;++j)
        pq.push(j);
    while (!pq.empty()){
        cerr<<pq.top()<<endl;
        pq.pop();
    }
}

当我用 g++、MSVC++ 和 clang 测试它时,它产生了预期的输出:

-1
-2
-3
-4
-5

但我还没有看到任何保证,即清除内部向量与在priority_queue不为空时调用pop()相同。尽管我知道清除它的其他方法,例如交换或使用空priority_queue分配它,但我认为如果这段代码可以正常工作,它会更有效,因为矢量中分配的内存是可重用的。所以我想知道这段代码是可移植的还是并不总是有效的?

但是我还没有看到任何保证,即清除内部向量与在priority_queue不为空时调用pop()相同。

因为那不是一回事。std::priority_queue是一种专门设计的容器适配器,通过严格的弱排序来保持物品的有序。如果未指定队列将具有的容器类型(在示例中未指定),则默认类型为 std::vector

因此,在非空优先级队列上调用 pop() 将具有从队列中删除顶部元素的效果,而对基础容器调用 clear() 将从队列中删除所有元素,而不仅仅是最顶层的元素。

尽管我知道清除它的其他方法,例如交换或使用空priority_queue分配它,但我认为如果这段代码可以正常工作,它会更有效,因为矢量中分配的内存是可重用的。所以我想知道这段代码是可移植的还是并不总是有效的?

根据参考文献,底层c成员对象是受保护的,因此应该保证跨编译器访问您的方式,也就是说,调用this->c.clear();应该是可移植的(有趣的是,它适用于旧版本的OpenBSD的g++ 4.2.1)。

就效率而言,这在某种程度上取决于。做一些类似this->c.clear();q = priority_queue <int>();在内存使用或复杂性方面可能没有太大区别,尽管您必须在不同的平台上对其进行测试才能验证。但是,做一些类似 this->c.clear(); vs. while(!q.empty()) { q.pop(); }更有效率。

在内存效率方面,优先级队列的pop函数调用底层容器pop_back函数,pop_backclear都不会影响底层向量的capacity,因此实际上没有任何"节省"以这种方式; 尽管有了这个,如果您有特定需要,您可以调整矢量的大小以增加/减少容量。

请记住,优先级队列pop函数调用函数pop_back底层容器,在空容器上调用pop_back未定义的行为

希望能有所帮助。

一个非常好的问题。虽然我似乎找不到任何严格的保证它是一种正确的方法,但有一些理由认为它是。

例如,考虑operator=的文档:

复制赋值运算符。将内容替换为 其他内容。有效地调用c = other.c;。(隐式 声明)

由于另一个队列的大小可能不同,这实质上意味着没有依赖于大小的内部状态。此外,它还意味着分配一个空队列实质上是用一个空队列替换容器,而不做任何其他事情。

考虑到这一点,以及优先级队列的合理实现几乎不需要维护任何状态的事实,除了队列的大小,我相信可以安全地假设清除底层容器是清空队列的有效方法。