std :: queue <t,list <t =“”>&gt; :: size()在O(n)中是否很慢?</t,>

时间:2011-10-18 14:28:58

标签: c++ performance stl queue

我遇到了使用队列的代码的意外性能行为。我意识到当队列中有更多元素时,性能会下降。事实证明,使用size()方法是原因。以下是一些显示问题的代码:

#include <queue>
#include <list>
#include <iostream>

#include "Stopwatch.h"

using namespace std;

struct BigStruct
{
    int x[100];
};
int main()
{
    CStopwatch queueTestSw;

    typedef BigStruct QueueElementType;
    typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;
    //typedef std::queue<QueueElementType > QueueType; //no surprise, this queue is fast and constant
    QueueType m_queue;

    for (int i=0;i<22000;i++)
        m_queue.push(QueueElementType());
    CStopwatch sw;
    sw.Start();
    int dummy;
    while (!m_queue.empty())
    {
        //remove 1000 elements:
        for (int i=0;i<1000;i++)
        {
            m_queue.pop();
        }
        //call size() 1000 times and see how long it takes
        sw = CStopwatch();
        sw.Start();
        for (int i=0;i<1000;i++)
        {   
            if (m_queue.size() == 123456)
            {
                dummy++;
            }
        }
        std::cout << m_queue.size() << " items left. time: " << sw.GetElapsedTimeInSeconds() << std::endl;  
    }   
    return dummy;


}

CStopwatch是使用clock_gettime(CLOCK_REALTIME, ..)的类。结果是:

21000 items left. time: 1.08725
20000 items left. time: 0.968897
19000 items left. time: 0.818259
18000 items left. time: 0.71495
17000 items left. time: 0.583725
16000 items left. time: 0.497451
15000 items left. time: 0.422712
14000 items left. time: 0.352949
13000 items left. time: 0.30133
12000 items left. time: 0.227588
11000 items left. time: 0.178617
10000 items left. time: 0.124512
9000 items left. time: 0.0893425
8000 items left. time: 0.0639174
7000 items left. time: 0.0476441
6000 items left. time: 0.033177
5000 items left. time: 0.0276136
4000 items left. time: 0.022112
3000 items left. time: 0.0163013
2000 items left. time: 0.0101932
1000 items left. time: 0.00506138

这似乎与http://www.cplusplus.com/reference/stl/queue/size/

相矛盾
  

复杂性:常数。

如果结构更大,问题会更严重。我正在使用GCC 4.3.2。

你能解释一下吗?有没有办法用列表解决这个问题?

(请注意,我需要将列表用作队列的基础容器,因为我需要不断的时间插入复杂性。)

3 个答案:

答案 0 :(得分:7)

queue是一个容器适配器,所以你必须明白复杂性描述可能只涉及适配器自身的工作(这确实是不变的,即只是传递调用通过底层容器。)

例如,see this referencesize()调用基础容器的size()函数。对于list,这在C ++ 98/03中具有复杂度O(n),在C ++ 11中具有O(1)。

答案 1 :(得分:5)

queue使用的是list容器,而不是deque默认容器:

typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;

大小需要O(n),你不应该感到惊讶,因为这是list容器预C ++ 11的完全有效的实现。该标准的先前版本不保证列表的size成员函数的复杂性。

如果您将代码更改为:

typedef std::queue<QueueElementType, std::deque<QueueElementType> > QueueType;

您将看到所需的行为(O(1)尺寸复杂度)。

答案 2 :(得分:1)

添加到Michael的答案:您使用std::list作为队列容器,因此size()方法取决于您的std :: list实现的大小。如果你在同一个网站上查找,你会发现http://www.cplusplus.com/reference/stl/list/size/,其复杂性在某些实现中是不变的,而在其他实现上则是线性的。如果您需要不断的插入和大小,那么您需要一个不同的数据结构或更好的std::list实现。