std :: deque :: push_back / front的复杂性要求

时间:2011-12-01 01:19:36

标签: c++ containers

由于几天前的this问题,有一些事情让我对std::deque::push_back/push_front与实际std::deque实施的复杂性要求有所不满。野。

上一个问题的结果是这些操作需要O(1)最坏情况的复杂性。我确认c++11确实存在这种情况:

  

来自23.3.3.4 deque修饰符,参考insert,push / emplace front / back

     

复杂性:插入的元素数量加上复杂度是线性的   到双端队列开始和结束的距离较小。插入单个   在deque的开头或结尾处的元素总是需要恒定的时间和   导致对T的构造函数的单个调用。

这与索引的O(1)复杂性要求相结合,通过operator[]等。

问题是实现并不严格满足这些要求。

msvcgcc而言,std::deque实现是一个被阻塞的数据结构,由指向(固定大小)块的动态指针组成,每个块存储一个数据元素的数量。

在最坏的情况下,push_back/front etc可能需要分配一个额外的块(这是很好的 - 固定大小分配是O(1)),但它也可能要求块指针的动态数组是调整大小 - 这不是很好,因为这是O(m),其中m是块的数量,在一天结束时是O(n)

显然,这仍然是摊销O(1)的复杂性,而且一般来说m << n在实践中它会非常快。但似乎存在一致性问题?

另外一点,我不知道如何设计一个严格满足O(1)push_back/front etc operator[]复杂度的数据结构。您可以拥有块指针的链接列表,但这不会为您提供所需的operator[]行为。真的可以吗?

2 个答案:

答案 0 :(得分:3)

在C ++ 11 FDIS中,我们可以阅读:

  

23.2.3序列容器[sequence.reqmts]

     

16 / 表101列出了为某些类型的序列容器而非其他序列容器提供的操作。实现应为“容器”列中显示的所有容器类型提供这些操作,并应实施它们以便摊销的恒定时间

其中表101 被命名为可选序列容器操作,并列出dequepush_back操作的push_front

因此,在您引用的段落中,它似乎更像是一个轻微的遗漏。也许值得一个缺陷报告?

请注意,对构造函数的调用仍然存在。

答案 1 :(得分:0)

我怀疑块指针的重新分配是以几何增加的大小完成的 - 这是std :: vector的常见技巧。我认为这在技术上是O(log m),但是当你指出m&lt;&lt; n,实际上它不会影响现实世界的结果。