I don't think one even needs that. A simple vector of pointers will work, e.g. Vec<Box<T>>
won't move the T
s on growth.
The second is not generally true: to insert into the middle, you’ll need to traverse the list until the middle, which takes linear time, see this talk by Bjarn Stroustrup for some benchmarks.
This is correct. Iff you need to find the list node in which you want to insert/erase/splice, then these operations are O(N) and not O(1) because of the find.
you are using a cursor API, edit and traverse list in changing directions at the same time then yes, it could be faster. But this is definitely an extremely niche use-case.
Iterators to linked-list nodes are not invalidated on insertion/splicing. They are only invalidated on erasure, and only those iterators that point to the erased nodes. Every reasonable doubly-linked list API exposes these invariants, and every reasonable program using linked lists relies on these invariants by keeping iterators to relevant nodes around. I cannot honestly believe that someone that knows enough to dump a vector in favor of a linked list will perform many insertions into the linked list middle by traversing the linked list from the front on every insertion [*].
The appropriate way of doing that is finding the middle once, which is O(N), and then inserting elements while updating the pointer, which is O(1) per element (or even better, O(1) independently of the number of elements being inserted if you are splicing from another list). Both operations are much faster than inserting into the middle of a non-tiny vector, and ridiculously faster as the number of elements in the sequence becomes large (one memory allocation and a couple of pointer swaps vs a memcpy
at best, and N/2
individual calls to clone
at worst).
So I disagree with your statement, that is not an extremely niche use-case, that's the only reasonable way of working with linked lists.
[*] FWIW Bjarne agrees. There was a Q&A session afterwards where he admitted that the benchmark intent was to prove the point that memcpy
ing half of the vector was faster than traversing a linked list up to its middle or somewhere else (the elements where randomly chosen I think?), and that in no way was this the proper way of working with a doubly-linked list, which was also kind of its point.