A deque<T>
может быть правильно реализовано с помощью vector<T*>
. Все элементы копируются в кучу, а указатели хранятся в векторе. (Подробнее о векторе позже).
Почему T*
вместо T
? Поскольку стандарт требует, чтобы
"Вставка в любой конец очереди делает недействительными все итераторы
в deque, но не оказывает влияния на достоверность ссылок на
элементы оформления."
(мой акцент). T*
помогает удовлетворить это. Это также помогает нам удовлетворить это:
"Вставка одного элемента в начале или в конце deque всегда ..... вызывает одиночный вызов конструктора T ."
Теперь для (спорных) бит. Зачем использовать vector
для хранения T*
? Это дает нам произвольный доступ, что является хорошим началом. Давайте на минутку забудем о сложности вектора и аккуратно подстроимся к этому:
Стандарт говорит о «количестве операций над содержащимися объектами». Для deque::push_front
это явно 1, потому что построен ровно один объект T
, и ноль из существующих T
объектов считывается или сканируется любым способом. Это число 1, очевидно, является константой и не зависит от количества объектов, находящихся в данный момент в деке. Это позволяет нам сказать, что:
'Для нашего deque::push_front
число операций над содержащимися объектами (Ts) фиксировано и не зависит от количества объектов, уже находящихся в очереди.'
Конечно, количество операций на T*
будет не таким хорошим. Когда vector<T*>
станет слишком большим, оно будет перераспределено, и многие T*
будут скопированы. Так что да, количество операций на T*
будет сильно отличаться, но на количество операций на T
это не повлияет.
Почему нас интересует это различие между операциями подсчета на T
и операциями подсчета на T*
? Это потому, что стандарт гласит:
Все требования к сложности, изложенные в этом разделе, изложены исключительно с точки зрения количества операций над содержащимися объектами.
Для deque
содержащимися объектами являются T
, а не T*
, что означает, что мы можем игнорировать любую операцию, которая копирует (или перераспределяет) T*
.
Я не очень много говорил о том, как вектор будет вести себя в деке. Возможно, мы интерпретируем его как кольцевой буфер (вектор всегда занимает максимум capacity()
, а затем перераспределяем все в больший буфер, когда вектор заполнен. Детали не имеют значения.
В последних нескольких абзацах мы проанализировали deque::push_front
и взаимосвязь между количеством объектов в уже существующей deque и числом операций, выполняемых push_front над содержащимися T
-объектами. И мы обнаружили, что они были независимы друг от друга. Поскольку стандарт требует, чтобы сложность выражалась в операциях на T
, то мы можем сказать, что это имеет постоянную сложность.
Да, сложность Operations-On-T * -1068 * амортизируется (из-за vector
), но нас интересует только Operations-On- T
- Сложность и это постоянная (не амортизированная).
Эпилог: сложность vector :: push_back или vector :: push_front не имеет значения в этой реализации; эти соображения связаны с операциями на T*
и, следовательно, не имеют значения.