The cost table: which collection, and why
Rust's standard library ships most of the structures an interview or a real service needs, in std::collections plus Vec itself. The skill is not memorising their APIs; it is knowing what each operation costs, so the right one is picked before the code is written. This module builds the classic structures by hand where that teaches something (a linked list, a tree), then shows the standard-library type real code would use.
| Type | Access | Search | Insert | Remove | Use it for |
|---|---|---|---|---|---|
Vec<T> | O(1) by index | O(n) | O(1) amortised at end, O(n) elsewhere | O(1) at end, O(n) elsewhere | The default. Lists, stacks, buffers |
VecDeque<T> | O(1) by index | O(n) | O(1) at both ends | O(1) at both ends | Queues, BFS, sliding windows |
HashMap<K, V> | — | O(1) average | O(1) average | O(1) average | Lookup by key, counting, caching |
BTreeMap<K, V> | — | O(log n) | O(log n) | O(log n) | Sorted keys, range queries, stable output |
HashSet<T> / BTreeSet<T> | — | O(1) avg / O(log n) | O(1) avg / O(log n) | O(1) avg / O(log n) | Membership, de-duplication |
BinaryHeap<T> | O(1) largest only | O(n) | O(log n) | O(log n) (largest) | Priority queues, top-k, Dijkstra |
| Linked list (by hand) | O(n) | O(n) | O(1) at head | O(1) at head | Learning ownership; rarely production |
| Binary search tree (by hand) | — | O(log n) balanced, O(n) worst | same | same | Learning recursion; use BTreeMap in production |
Vec wins more often than the table suggests: its elements sit next to each other in memory, so the CPU cache loads them in batches. A linear scan of a 1,000-element Vec often beats a "faster" structure that chases pointers around the heap.
fn main() {
let mut v: Vec<i32> = Vec::with_capacity(4);
v.push(10);
v.push(20);
v.extend([30, 40, 50]);
println!("len = {}, first = {}, last = {:?}", v.len(), v[0], v.last());
println!("slice [1..3] = {:?}", &v[1..3]);
println!("contains 30? {}", v.contains(&30));
println!("get(99) = {:?}", v.get(99));
v.insert(0, 5); // O(n): shifts every element right
v.retain(|&x| x % 20 != 0);
println!("{:?}", v);
}len = 5, first = 10, last = Some(50)
slice [1..3] = [20, 30]
contains 30? true
get(99) = None
[5, 10, 30, 50]v[99] would panic; v.get(99) returns None. Prefer get whenever the index comes from outside the function.
Replace retain with v.dedup() after pushing a duplicate value twice in a row, and print the result.
