Rust 红黑树锈迹斑斑,越来越';应为结构节点,找到可变引用';
我试图实现红黑树生锈。经过两天与编译器的斗争,我准备放弃,我在这里寻求帮助 这个问题对我帮助很大: 我查看了Rust中RB树的现有示例代码,但是我看到的所有示例代码都使用了某种形式的不安全操作或Rust 红黑树锈迹斑斑,越来越';应为结构节点,找到可变引用';,rust,red-black-tree-insertion,Rust,Red Black Tree Insertion,我试图实现红黑树生锈。经过两天与编译器的斗争,我准备放弃,我在这里寻求帮助 这个问题对我帮助很大: 我查看了Rust中RB树的现有示例代码,但是我看到的所有示例代码都使用了某种形式的不安全操作或null,我们不应该在这里使用这些操作 我有以下代码: #[derive(Debug, Clone, PartialEq)] pub enum Colour { Red, Black, } type T_Node<T> = Option<Box<Node<T
null
,我们不应该在这里使用这些操作
我有以下代码:
#[derive(Debug, Clone, PartialEq)]
pub enum Colour {
Red,
Black,
}
type T_Node<T> = Option<Box<Node<T>>>;
#[derive(Debug, Clone, PartialEq)]
pub struct Node<T: Copy + Clone + Ord> {
value: T,
colour: Colour,
parent: T_Node<T>,
left: T_Node<T>,
right: T_Node<T>,
}
impl<T: Copy + Clone + Ord> Node<T>
{
pub fn new(value: T) -> Node<T>
{
Node {
value: value,
colour: Colour::Red, // add a new node as red, then fix violations
parent: None,
left: None,
right: None,
// height: 1,
}
}
pub fn insert(&mut self, value: T)
{
if self.value == value
{
return;
}
let mut leaf = if value < self.value { &mut self.left } else { &mut self.right };
match leaf
{
None =>
{
let mut new_node = Node::new(value);
new_node.parent = Some(Box::new(self));
new_node.colour = Colour::Red;
(*leaf) = Some(Box::new(new_node));
},
Some(ref mut leaf) =>
{
leaf.insert(value);
}
};
}
}
#[派生(调试、克隆、部分Q)]
酒吧枚举颜色{
红色
黑色
}
类型T_Node=选项;
#[派生(调试、克隆、PartialEq)]
发布结构节点{
值:T,
颜色:颜色,
父节点:T_节点,
左:T_节点,
右:T_节点,
}
impl节点
{
pub fn new(值:T)->节点
{
节点{
价值:价值,
color:color::Red,//将新节点添加为红色,然后修复冲突
家长:没有,
左:没有,
右:没有,
//身高:1,,
}
}
发布fn插入(&mut self,值:T)
{
如果self.value==value
{
返回;
}
设mut-leaf=if-value
{
让mut new_node=node::new(值);
new_node.parent=Some(Box::new(self));
新节点颜色=颜色::红色;
(*leaf)=一些(Box::new(new_节点));
},
一些(参考多叶)=>
{
叶。插入(值);
}
};
}
}
行new_node.parent=Some(Box::new(self))代码>告诉我错误。
我理解错误发生的原因(self
被声明为可变引用),我不知道如何解决这个问题,但我需要self
成为可变引用,这样我就可以修改我的树(除非你能提出更好的建议)
我试图将T_节点
声明为具有可变引用,而不仅仅是节点
,但这只会产生更多问题
我也愿意接受关于更好地选择变量类型的建议
非常感谢您的帮助。设计中存在一些缺陷,如果不做一些修改,就无法进一步改进
首先,Box
不支持共享所有权,但您需要共享所有权,因为同一节点由父节点(rbtree.right/rbtree.left)和子节点(rbtree.parent)引用。为此你需要
因此,您需要切换到Rc
,而不是Box
:
类型T_节点=选项;
但这并不能解决问题。现在,您的节点位于Rc
内部,Rc
不允许对其内容进行变异(您可以通过进行变异,但这要求它是唯一的,在您的情况下,它不是常数)。除非你能变异一个节点,否则你将无法对你的树做很多事情
所以你需要使用。为此,我们将添加一个附加层
类型T_节点=选项;
现在,这将允许我们改变里面的内容
但这并不能解决问题。由于您还需要保留从子对象到父对象的引用,因此最终将创建一个引用循环
幸运的是:
为了使子节点知道其父节点,我们需要向节点结构定义中添加一个父字段。问题在于决定父母应该是什么类型。我们知道它不能包含Rc,因为这将创建一个引用循环,其中leaf.parent指向branch,branch.children指向leaf,这将导致它们的强_计数值永远不会为0。从另一个角度考虑关系,父节点应该拥有它的子节点:如果父节点被删除,它的子节点也应该被删除。但是,子节点不应该拥有其父节点:如果我们删除子节点,父节点应该仍然存在。这是一个弱引用的例子
所以我们需要child持有对parent的弱引用。这可以通过以下方式实现:
type Child=Option;
输入Parent=Option;
现在我们已经固定了大部分设计
我们应该做的另一件事是,不直接公开节点
,而是将其封装在结构RBTree
中,该结构将保存树的根
,并且可以在RBTree
上调用插入
、搜索
、删除
等操作。这将使事情变得简单,实现将变得更符合逻辑
pub结构RBTree{
根:孩子,
}
现在,让我们编写一个类似于您的insert
实现:
impl-RBTree{
发布fn插入(&mut self,值:T){
fn插入(子节点:&mut子节点,mut新节点:节点){
让child=child.as_ref().unwrap();
让mut child_mut_borrow=child.borrow_mut();
如果child_mut_borrow.value==new_node.value{
返回;
}
let leaf=如果子节点\u mut\u borrow.value>new\u node.value{
&多个孩子,多个借用,左
}否则{
&多孩子多借钱,对吗
};
火柴叶{
一些())=>{
插入(叶,新节点);
}
无=>{
new_node.parent=Some(Rc::降级(&child));
*叶=一些(Rc::new(RefCell::new(new_节点));
}
};
}
让mut new_node=node::new(值);
如果self.root.is_none(){
new_node.parent=无;
self.root=Some(Rc::new(RefCell::new(new_节点));
}否则{
//我们确保从不向insert()发送“无”
插入(&mut self.root,新节点);
}
}
}
我在RBTr中定义了insert
函数