As a result of this question from a few days ago there are a few things that have been bugging me about the complexity requirements for std::deque::push_back/push_front
vs the actual std::deque
implementations out in the wild.
The upshot of the previous question was that these operations are required to have O(1)
worst case complexity. I verified that this was indeed the case in c++11
:
from 23.3.3.4 deque modifiers, refering to insert, push/emplace front/back
Complexity: The complexity is linear in the number of elements inserted plus the lesser of the distances to the beginning and end of the deque. Inserting a single element either at the beginning or end of a deque always takes constant time and causes a single call to a constructor of T.
This is combined with the O(1)
complexity requirement for indexing, via operator[]
etc.
The issue is that implementations don't strictly satisfy these requirements.
In terms of both msvc
and gcc
the std::deque
implementation is a blocked data structure, consisting of a dynamic array of pointers to (fixed size) blocks, where each block stores a number of data elements.
In the worst case, push_back/front etc
could require an extra block to be allocated (which is fine - fixed size allocation is O(1)
), but it could also require that the dynamic array of block pointers be resized - this is not fine, since this is O(m)
where m
is the number of blocks, which at the end of the day is O(n)
.
Obviously this is still amortised O(1)
complexity and since generally m << n
it's going to be pretty fast in practice. But it seems there's an issue with conformance?
As a further point, I don't see how you can design a data structure that strictly satisfies both the O(1)
complexity for both push_back/front etc
and operator[]
. You could have a linked-list of block pointers, but this doesn't give you the desired operator[]
behaviour. Can it actually be done?