面试题答案
一键面试自定义容器实现
use std::mem;
struct CustomVec<T> {
data: Vec<T>,
}
impl<T> CustomVec<T> {
fn new() -> Self {
CustomVec { data: Vec::new() }
}
fn insert(&mut self, index: usize, value: T) {
if index > self.data.len() {
panic!("Index out of bounds");
}
self.data.push(mem::replace(&mut self.data.get_mut(index).unwrap_or_else(|| {
self.data.push(value);
self.data.last_mut().unwrap()
}), value));
}
fn remove(&mut self, index: usize) -> Option<T> {
if index >= self.data.len() {
return None;
}
let last = self.data.pop();
if let Some(last) = last {
if index < self.data.len() {
*self.data.get_mut(index).unwrap() = last;
}
}
self.data.pop()
}
}
内存安全说明
- 避免内存泄漏:
- Rust的所有权系统确保当对象不再被使用时,其内存会被自动释放。在
insert
和remove
操作中,我们使用mem::replace
来安全地替换值,而pop
方法在移除元素时会释放其内存。
- Rust的所有权系统确保当对象不再被使用时,其内存会被自动释放。在
- 避免悬空指针:
- Rust不允许悬空指针。在
remove
操作中,我们通过将最后一个元素移动到被删除元素的位置,然后移除最后一个元素,确保没有指针指向已释放的内存。
- Rust不允许悬空指针。在
性能对比
- 随机插入:
- 标准
Vec
:标准Vec
的insert
操作平均时间复杂度为O(n),因为在插入新元素时,需要将插入位置之后的所有元素向后移动。 - 自定义
CustomVec
:自定义CustomVec
的insert
操作平均时间复杂度为O(1),因为我们只是将最后一个元素与插入位置的元素交换,然后将新元素插入到最后。
- 标准
- 随机删除:
- 标准
Vec
:标准Vec
的remove
操作平均时间复杂度为O(n),因为在删除元素时,需要将删除位置之后的所有元素向前移动。 - 自定义
CustomVec
:自定义CustomVec
的remove
操作平均时间复杂度为O(1),因为我们只是将最后一个元素移动到删除位置,然后移除最后一个元素。
- 标准
然而,在实际使用中,CustomVec
可能会导致数据在内存中的布局不连续,从而影响缓存命中率,特别是在频繁进行插入和删除操作之后。标准Vec
保证数据在内存中是连续的,对于需要顺序访问的场景可能更高效。