教科书里链表两端插入 O(1)、拼接 O(1),但在 Rust 里它很少是第一选择。这篇用分配器计数和 release 计时验证:每个元素一次堆分配、遍历慢几倍、连 push_back 也不占优,链表只赢在 append。
编译:成功
运行(退出码 0):
LinkedList<u64> 1000 个元素: alloc 1000 次, 每次 24 字节(元素本身 8 字节), 共申请 24000 字节
Vec<u64> 1000 个元素: alloc 1 次 realloc 8 次, 共申请 16352 字节(含扩容过程中的所有申请)
size_of::<LinkedList<u64>>() = 24 size_of::<Vec<u64>>() = 24 编译:成功
运行(退出码 0):
遍历求和 100 万个 u64: LinkedList 最快 0.659 ms Vec 最快 0.132 ms数字是本机 release 模式下的实测;节点在一个干净的堆上连续分配,真实程序里堆碎片化后链表通常更慢,但这一点没有测。
编译:成功
运行(退出码 0):
push_back 100 万次: LinkedList 8.50 ms VecDeque 1.41 ms
push_back 100 万次: LinkedList 7.22 ms VecDeque 1.43 ms
push_back 100 万次: LinkedList 6.35 ms VecDeque 1.22 ms
两个 100 万元素的容器拼接: LinkedList::append 209ns Vec::append 715.5µs (拼接后长度 2000000 / 2000000)两端队列用 VecDeque 环形缓冲区。
源码:
1 | use std::collections::LinkedList;
2 | fn main() {
3 | let l: LinkedList<i32> = (1..=5).collect();
4 | println!("{}", l[2]);
5 | }
编译:失败
error[E0608]: cannot index into a value of type `LinkedList<i32>`
--> <实验目录>/src/u58d.rs:4:21
|
4 | println!("{}", l[2]);
| ^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0608`.
编译:成功
运行(退出码 0):
iter().nth( 10) = Some(10) 用时 417ns
iter().nth( 1000) = Some(1000) 用时 2.542µs
iter().nth(100000) = Some(100000) 用时 75.083µs
iter().nth(900000) = Some(900000) 用时 805.625µs
split_off(2): 前 [0, 1] 后 [2, 3, 4]