Я думаю, что вам лучше подать диаграмму ... давайте поиграем с искусством ASCII!
Как правило, deque - это массив фрагментов памяти, но все вместе, передний и задний блоки памяти заполнены,Это необходимо, поскольку deque является RandomAccessContainer, и для получения O (1) доступа к любому контейнеру у вас не может быть неограниченного количества контейнеров, из которых можно прочитать размер:
bool size() const { return first.size + (buckets.size()- 2) * SIZE + last.size; }
T& operator[](size_t i) {
if (i < first.size) { return first[SIZE - i]; }
size_t const correctedIndex = i - first.size;
return buckets[correctedIndex / SIZE][correctedIndex % SIZE];
}
Эти операции выполняются O(1) из-за умножения / деления!
В моем примере я предполагаю, что блок памяти заполнен, когда он содержит 8 элементов.На практике никто не говорил, что размер должен быть фиксированным, просто все внутренние сегменты должны иметь одинаковый размер.
// Deque
0: ++
1: ++++++++
2: ++++++++
3: ++++++++
4: +++++
Теперь скажите, что мы хотим вставить индекс 13. Он падает где-то в сегменте с пометкой 2Есть несколько стратегий, о которых мы можем подумать:
- расширение корзины 2 (только)
- введение нового сегмента до или после 2 и перетасовывание только нескольких элементов
Но эти две стратегии нарушили бы инвариант, согласно которому все "внутренние" сегменты имеют одинаковое количество элементов.
Поэтому нам остается перетасовывать элементы вокруг, либо к началу, либо к концу (в зависимости от того, что дешевле), в нашем случае:
// Deque
0: +++
1: ++++++++
2: +O++++++
3: ++++++++
4: +++++
Обратите внимание, как выросла корзина 0.
Эта случайная последовательность подразумевает, что в худшем случае вы будете двигатьсяполовина элементов: O (N / 2).
deque
имеет вставку O (1) либо в начале, либо в конце, потому что это просто вопрос добавления элемента в нужном месте или(если ведро фуll) создание нового сегмента.
Существуют другие контейнеры, которые имеют лучшее поведение вставки / удаления при случайных индексах, основанные на B + Trees .В индексированном дереве B + вы можете вместо «ключа» (или параллельно) вести внутреннее подсчет элементов до определенной позиции.Существуют различные методы, чтобы сделать это эффективно.В конце вы получите контейнер с:
- O (1): пустой, размер
- O (log N): at, insert, erase
Вы можете проверить модуль blist
в Python, который реализует элемент, подобный списку Python, поддерживаемый такой структурой.