I am trying to implement a BST in Rust. My struct looks like this:
pub struct Node<T> {
key: T,
parent: Option<Box<Node<T>>>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
I am working on a method for finding the successor of a current node. After a prolonged fight with the borrow checker, I made it work, but it now looks like this:
//If right node exists - successor is a min node in it.
//Else - go up a parent node. If parent is None, no successor.
//If origin was parent's left node - parent is a successor.
//Else - go up another level.
pub fn succ(&self) -> Option<Box<Node<T>>> {
match self.right {
Some(ref node) => Some(node.min()),
None => {
let mut origin = Box::new(self.clone()); //To match types
let mut parent = origin.parent.clone(); //`Node<T>` not a copy type
loop {
let parent_node = match parent.clone() {
Some(node) => node,
None => break,
};
let right_of_parent = match parent_node.clone().right {
Some(node) => node,
None => break,
};
if *origin != *right_of_parent {
break;
}
origin = parent_node;
parent = origin.parent.clone();
}
parent
}
}
}
If I remove all the .clone()
s, the compiler starts crying with "partial moved value" and "cannot assign because borrowed" errors. Is there a way to make this code more idiomatic and less of a cloning hell?
UPD:
Wanted to post the solution I ended up with.
First of all, above code doesn't work, as the parent field contained not a reference, but a copy of a parent node. So in the end the question turned into "how to implement a reference to a parent node".
I considered the answer below, some books and relevant answers and in the end i came to conclusion that it don't worth it for a toy project that I didn't even plan to publish online. I've found not the most efficient, but definitely simpler solution - not to use parent reference at all.
I removed parent field from the structure above and created another structure:
pub struct Tree<T> {
root: Option<Box<Node<T>>>,
}
And now I search for parent from the root of the tree. My succ
function now looks like this:
fn succ<'a>(&'a self, node: &'a Node<T>) -> Option<&Node<T>> {
match node.right {
Some(ref rnode) => rnode.min(),
None => {
let mut succ = None;
let mut root = self.root.as_ref();
loop {
root = match root {
Some(ref rootnode) => {
match node.key.cmp(&rootnode.key) {
Ordering::Less => {
succ = Some(&***rootnode);
rootnode.left.as_ref()
}
Ordering::Greater => rootnode.right.as_ref(),
Ordering::Equal => break,
}
}
None => break,
}
}
succ
}
}
}