Se podría ser O (1) si la lista almacenaría una bandera que permite intercambiar el significado de los “ prev
” y “ next
” punteros de cada nodo. Si invertir la lista sería una operación frecuente, tal adición podría ser de hecho útil y no sé de ninguna razón por la cual la norma actual prohibiría su implementación . Sin embargo, tener dicha bandera haría que el recorrido ordinario de la lista sea más costoso (aunque solo sea por un factor constante) porque en lugar de
current = current->next;
en el operator++
iterador de la lista, obtendría
if (reversed)
current = current->prev;
else
current = current->next;
que no es algo que decidas agregar fácilmente. Dado que las listas generalmente se recorren con mucha más frecuencia de lo que se invierten, sería muy imprudente que el estándar ordenara esta técnica. Por lo tanto, se permite que la operación inversa tenga una complejidad lineal. Sin embargo, tenga en cuenta que t ∈ O (1) ⇒ t ∈ O ( n ) por lo que, como se mencionó anteriormente, la implementación de su "optimización" técnicamente estaría permitida.
Si proviene de un entorno Java o similar, es posible que se pregunte por qué el iterador debe verificar la bandera cada vez. ¿No podríamos tener dos tipos de iteradores distintos, ambos derivados de un tipo base común, y tener std::list::begin
y std::list::rbegin
polimórficamente devolver el iterador apropiado? Si bien es posible, esto empeoraría aún más las cosas porque avanzar el iterador sería una llamada de función indirecta (difícil de alinear) ahora. En Java, está pagando este precio de forma rutinaria de todos modos, pero, de nuevo, esta es una de las razones por las que muchas personas recurren a C ++ cuando el rendimiento es crítico.
Como señaló Benjamin Lindley en los comentarios, dado reverse
que no está permitido invalidar iteradores, el único enfoque permitido por el estándar parece ser almacenar un puntero en la lista dentro del iterador que causa un acceso doble indirecto a la memoria.