Это может быть O (1), если список будет хранить флаг, который позволяет менять значение указателей « prev
» и « next
» каждого узла. Если обращение к списку будет частой операцией, такое добавление может быть действительно полезным, и я не знаю ни одной причины, по которой его реализация будет запрещена действующим стандартом. Однако наличие такого флага сделало бы обычный обход списка более дорогим (хотя бы с постоянным коэффициентом), потому что вместо
current = current->next;
в operator++
итераторе списка вы получите
if (reversed)
current = current->prev;
else
current = current->next;
это не то, что вы решили бы добавить легко. Учитывая , что списки обычно проходится гораздо чаще , чем они поменялись местами, было бы очень неразумно стандарт для санкционировать эту технику. Следовательно, обратная операция может иметь линейную сложность. Заметим, однако, что t ∈ O (1) ⇒ t ∈ O ( n ), поэтому, как упоминалось ранее, техническая реализация вашей «оптимизации» будет разрешена.
Если вы пришли из Java или из аналогичного фона, вы можете спросить, почему итератор должен каждый раз проверять флаг. Не могли бы мы вместо этого иметь два разных типа итераторов, оба производных от общего базового типа, а также иметь std::list::begin
и std::list::rbegin
полиморфно возвращать соответствующий итератор? Хотя это и возможно, это еще больше ухудшит ситуацию, поскольку продвижение итератора теперь будет косвенным (трудно встроенным) вызовом функции. В Java вы все равно платите эту цену регулярно, но опять же, это одна из причин, по которой многие люди обращаются к C ++, когда производительность критична.
Как отметил Бенджамин Линдли в комментариях, поскольку reverse
недопустимо делать недействительными итераторы, единственным подходом, допускаемым стандартом, кажется, является сохранение указателя на список внутри итератора, который вызывает двойной косвенный доступ к памяти.