You can write your function like this:
fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
if vec.get(index).is_none() {
None
} else {
Some(vec.swap_remove(index))
}
}
The code you see here (get
and swap_remove
) is guaranteed O(1).
However, kind of hidden, vec
is dropped at the end of the function and this drop operation is likely not O(1), but O(n) (where n is vec.len()
). If T
implements Drop
, then drop()
is called for every element still inside the vector, meaning dropping the vector is guaranteed O(n). If T
does not implement Drop
, then the Vec
only needs to deallocate the memory. The time complexity of the dealloc
operation depends on the allocator and is not specified, so we cannot assume it is O(1).
To mention another solution using iterators:
fn take<T>(vec: Vec<T>, index: usize) -> Option<T> {
vec.into_iter().nth(index)
}
I was about to write this:
While Iterator::nth()
usually is a linear time operation, the iterator over a vector overrides this method to make it a O(1) operation.
But then I noticed, that this is only true for the iterator which iterates over slices. The std::vec::IntoIter
iterator which would be used in the code above, doesn't override nth()
. It has been attempted here, but it doesn't seem to be that easy.
So, as of right now, the iterator solution above is a O(n) operation! Not to mention the time needed to drop the vector, as explained above.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…