-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(store): implement AvlTree::remove
#141
Conversation
I noticed that the current implementation uses For example, I want to refactor the following basecoin-rs/crates/store/src/avl/tree.rs Lines 66 to 78 in ef13279
to
|
AvlTree::remove
AvlTree::remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first pass on this, found the multiple recursive functions and the mem::replace()
s make the code a bit unclear, making it harder to say there are no issues with the code :)
basecoin/store/src/avl/tree.rs
Outdated
assert!(std::mem::replace(&mut leftmost_node.left, node.left.take()).is_none()); | ||
} | ||
std::mem::replace(node_ref, leftmost_node_ref) | ||
} else if node.left.is_some() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess here, since there is no right
child, we could have just linked the node
s parent to the left
child. Would require changes in remove_rec
though. But wouldn't need the remove_leftmost
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was very helpful ! 😄 It ended up not requiring remove_rightmost
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up keeping the same code (with a slight modification) - but handling the no-sibling cases separately.
basecoin/store/src/avl/tree.rs
Outdated
// Remove the leftmost node in the right subtree and replace the current. | ||
let mut leftmost_node_ref = AvlTree::remove_leftmost(&mut node.right); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside this remove_leftmost
function we also take the leftmost
's right child and put it in the leftmost
's parent left child.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really sure if this was a note. Note that, removed nodes are always a leaf. This is an invariant. Their left and right nodes are set to None
.
So, what I am doing here is:
- point
leftmost_node.left
to wherenode.left
points. - point
leftmost_node.right
to wherenode.right
points. (since, I called,node.{right,left}.take()
,node
is now a leaf too.) - replace
node
withleftmost_node
and return the old replaced value (which is a leaf) as the removed value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry it was a note, that remove_leftmost
had a misleading name for me in the beginning.
basecoin/store/src/avl/tree.rs
Outdated
assert!( | ||
std::mem::replace(&mut leftmost_node.right, node.right.take()).is_none() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this the same as:
leftmost_node.right = node.right.take();
Why do we need mem::replace
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right. I just wanted to assert the condition in one line. 8958a20
basecoin/store/src/avl/tests.rs
Outdated
} | ||
} | ||
|
||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be good to have a test where we remove one key and make sure the others are still present and the tree is balanced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. I am now testing balancing factor and present keys after each insert and delete.
dc91865
to
e1fc66f
Compare
e1fc66f
to
c8cfa04
Compare
This PR should remove/deprecate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Closes #140
A short summary of how
AvlTree::remove
is implemented,None
.Also, the current node's children are set to the new node's children.
This runs in
O(log(n))
as the recursive calls are always made on a subtree.