Я хочу удалить элементы из вектора в обратном порядке, начиная с последнего элемента. Насколько мне известно, самый простой способ сделать это с помощью итератора:

std::vector<int> data = ...
std::vector<int>::iterator iter;
for(iter = data.end() - 1; iter != data.begin() - 1; iter--) {
    data.erase(iter);
}

Мой вопрос: будет ли каждый из этих вызовов erase () иметь значение O (1), поскольку мы удаляем в конце, даже если общая сложность удаления составляет O (n)? Кроме того, является ли этот код «безопасным», если в векторе есть хотя бы 1 элемент?

3
donnyton 13 Апр 2014 в 03:19

3 ответа

Лучший ответ

Нет, в вашем алгоритме есть UB. Если бы это было не так, было бы O (n).
Изменение тела на это приведет к удалению UB: iter = data.erase(iter);
Почему? Потому что vector.erase() ведет себя так:

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

Если вы переписываете цикл таким образом, он будет работать даже для пустого контейнера:

for(auto it = data.end(); it!=data.begin(); it = data.erase(it-1)) /**/;

Это равно:

std::remove_if(data.rbegin(), data.rend(), [](data::reference x){return true;});

В любом случае, использование data.clear(), data.resize(0) или замена временного пустого вектора, скорее всего, будет быстрее.

4
Deduplicator 13 Апр 2014 в 00:08

Если вам действительно не нужно удалять их в обратном порядке, лучше просто позвонить data.clear().

В противном случае нет, это небезопасно: формирование data.begin() - 1 не определено, и уменьшение iter после того, как вы вызвали .erase, также не определено. Deduplicator опубликовал хорошее исправление для этого.

3
Community 23 Май 2017 в 11:58

Вроде. Сложность std :: vector erase () равна

Линейный по количеству стертых элементов (разрушений) плюс количество элементов после удаления последнего элемента (перемещения).

На основе этого источника: http://www.cplusplus.com/reference/vector/vector / erase /

Поскольку вы удаляете только один элемент и его последний, он линейный с N = 1, который можно интерпретировать как константу O (1).

0
Manuel Arwed Schmidt 12 Апр 2014 в 23:23