面试题答案
一键面试- 实现思路
- 对于树状结构中节点可能被多个其他节点共享引用的情况,我们需要使用能支持共享所有权的智能指针。同时,为了避免循环引用导致的内存泄漏,我们要合理设计数据结构和指针的使用。
- 采用
Rc
(引用计数)智能指针来处理共享所有权,它能减少不必要的内存复制,因为多个指针可以指向同一块内存,通过引用计数来管理内存的释放。当引用计数降为0时,内存被自动释放。 - 对于可能出现循环引用的情况,引入
Weak
指针。Weak
指针是一种弱引用,它不会增加引用计数,主要用于打破循环引用。当所有的Rc
指针都被释放后,即使存在Weak
指针,相关内存也会被释放。
- 涉及的智能指针类型及其使用方式
Rc<T>
- 定义树节点结构:
use std::rc::Rc;
struct TreeNode<T> {
value: T,
children: Vec<Rc<TreeNode<T>>>,
}
- **创建和使用节点**:
fn main() {
let root = Rc::new(TreeNode {
value: 1,
children: Vec::new(),
});
let child1 = Rc::new(TreeNode {
value: 2,
children: Vec::new(),
});
let child2 = Rc::new(TreeNode {
value: 3,
children: Vec::new(),
});
root.children.push(Rc::clone(&child1));
root.children.push(Rc::clone(&child2));
}
Weak<T>
:当存在可能的循环引用场景时使用。例如,假设树节点需要反向引用父节点,这可能导致循环引用。
use std::rc::{Rc, Weak};
struct TreeNodeWithParent<T> {
value: T,
children: Vec<Rc<TreeNodeWithParent<T>>>,
parent: Option<Weak<TreeNodeWithParent<T>>>,
}
- 打破循环引用:
fn main() {
let root = Rc::new(TreeNodeWithParent {
value: 1,
children: Vec::new(),
parent: None,
});
let child = Rc::new(TreeNodeWithParent {
value: 2,
children: Vec::new(),
parent: Some(Rc::downgrade(&root)),
});
root.children.push(Rc::clone(&child));
}
在上述代码中,child
通过Weak
指针parent
指向root
,而不是使用Rc
指针,这样即使root
的children
中包含child
,也不会形成循环引用导致内存泄漏。因为Weak
指针不会增加引用计数,当root
和child
的Rc
引用计数都降为0时,相关内存会被释放。