Сложность удаления элементов в векторах и deque

Я читал, что сложность добавления элементов в конец std::vector амортизируется с постоянной и вставки элементов в верхней и нижней части std::deque постоянна.Поскольку оба этих контейнера имеют итератор произвольного доступа, доступ к элементам с любым индексом является постоянным. Пожалуйста, дайте мне знать,если я ошибаюсь.Мой вопрос: если доступ к элементу в std::vector или std::deque является константой, тогда почему временная сложность удаления элемента через стирание O(n). Один из ответы здесь здесь говорится, что удаление элементов через erase равно O (n). Я знаю, что erase удаляет элементы между начальными итераторами и конечным, поэтому ответ в основном означает, что его O(n) в зависимости от отсутствия элементов между двумя итераторами и того, что удаление одного элемента из вектора / deque в любом индексе будет равно нулю?

3 ответов


вещи немного отличаются для std::vector и std::deque, а также они отличаются для C++98 и C++11.

std:: vector

сложность std::vector::erase() линейно как по длине стираемого диапазона, так и по количеству элементов между концом диапазона и концом контейнера (поэтому стирание элемента с конца занимает постоянное время).

C++2003 [lib.vector.modifiers] гласит:

iterator erase(iterator position);
iterator erase(iterator first, iterator last);`

...

сложность: деструктор T называется число раз, равное количеству элементов стер, но ... --29-->оператор присваивания of T называется число раз, равное числу элементов в векторе после стираемых элементов.

C++14 проект N4140 [vector.modifiers] гласит:

сложность: деструктор T называется число раз, равное количество элементов стерто, но двигаться оператор присваивания of T называется число раз, равное количеству элементы в векторе после стираемых элементов.

таким образом, вы видите, что реализация c++11/14 в целом более эффективна, поскольку она выполняет назначение перемещения вместо назначения копирования, но сложность остается той же.

std:: deque

сложность std::deque::erase() линейно как к длина диапазона стерта и до минимум из двух чисел: количество оставшихся элементов до начала серии, и количество оставшихся элементов после окончания серии. Таким образом, стирание элемента либо с начала, либо с конца занимает постоянное время.

C++2003 [lib.deque.modifiers]:

iterator erase(iterator position);
iterator erase(iterator first, iterator last);

сложность: количество вызовов деструктора такое же, как и количество стираемых элементов, но число вызов оператора присваивания имеет вид максимум равный минимуму количества элементов до стираемых элементов и количество элементов после стираемых элементов.

C++14 проект N4140 [deque.modifiers]/5:

сложность: число вызовов деструктора совпадает с числом стираемых элементов, но число вызовов оператора присваивания равно не больше чем меньше количество элементов до стираемых элементов и количество элементов после стираемых элементов.

так вот, то же самое и в C++98 и C++11/14, опять же за исключением того, что c++11 может выбрать между перемещение назначения и скопировать задание (здесь я вижу некоторые несоответствия в стандартной, потому что слова не говоря уже о мове задание для std::vector - может быть причиной другой вопрос).

обратите внимание также на "не более "и" не более " в формулировках. Этот позволяет реализациям быть более эффективными, чем линейные, хотя на практике они линейны (демо).


стирание элемента в векторе равно O (n), так как после удаления элемента вам все равно нужно переместить все последовательные элементы, чтобы заполнить созданный пробел. Если вектор имеет n элементов, то в худшем случае вам нужно будет сдвинуть n-1 элементов, следовательно, сложность O(n).


удаление элементов действительно O(n) не из-за того, что вы должны сделать, чтобы найти элемент для удаления, но из-за того, что вы должны сделать со всеми из них после его. Эти элементы должны быть сдвинуты вниз, чтобы заполнить пустой слот.

таким образом, в среднем стирание займет элемент примерно на полпути через вектор, поэтому вам придется сдвинуть около половины элементов. Отсюда O(n). В лучшем случае, вы стираете последний элемент - нет необходимости скользить. В худшем случае вы сотрете первый элемент - должны затем перейти другой элемент.