Si potrebbe essere O (1) se la lista potrebbe memorizzare un flag che permette di scambiare il significato del “ prev
” e “ next
” puntatori ogni nodo ha. Se invertire l'elenco sarebbe un'operazione frequente, tale aggiunta potrebbe in effetti essere utile e non conosco alcun motivo per cui implementarla sarebbe vietata dalla norma attuale. Tuttavia, avere una tale bandiera renderebbe la corsa ordinaria dell'elenco più costosa (se non altro per un fattore costante) perché invece di
current = current->next;
nella operator++
lista dell'iteratore, otterresti
if (reversed)
current = current->prev;
else
current = current->next;
che non è qualcosa che potresti decidere di aggiungere facilmente. Dato che gli elenchi vengono solitamente attraversati molto più spesso di quanto non siano invertiti, sarebbe poco saggio che lo standard imponga questa tecnica. Pertanto, l'operazione inversa può avere una complessità lineare. Si noti, tuttavia, che t ∈ O (1) ⇒ t ∈ O ( n ), quindi, come menzionato in precedenza, l'implementazione della "ottimizzazione" tecnicamente sarebbe consentita.
Se provieni da uno sfondo Java o simile, potresti chiederti perché l'iteratore deve controllare la bandiera ogni volta. Non potremmo invece avere due tipi di iteratori distinti, entrambi derivati da un tipo di base comune, e avere std::list::begin
e std::list::rbegin
restituire polimorficamente l'iteratore appropriato? Se possibile, ciò renderebbe il tutto ancora peggio perché far avanzare l'iteratore sarebbe una chiamata di funzione indiretta (difficile da incorporare) ora. In Java, si paga comunque questo prezzo regolarmente, ma ancora una volta, questo è uno dei motivi per cui molte persone cercano C ++ quando le prestazioni sono fondamentali.
Come sottolineato da Benjamin Lindley nei commenti, poiché reverse
non è consentito invalidare gli iteratori, l'unico approccio consentito dallo standard sembra essere quello di memorizzare un puntatore all'elenco all'interno dell'iteratore che provoca un accesso alla memoria doppio indiretto.