-
Notifications
You must be signed in to change notification settings - Fork 0
Make functional BST more-functional. #6
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,38 @@ | |
//! expect to modify the tree (e.g. `insert` or `delete`) instead return | ||
//! a new tree that reference many of the nodes of the original tree. | ||
//! | ||
//! To avoid copious `Rc`ing, we do not implement a particularly efficient | ||
//! persistent structure - we only allow one tree at a time. Still, most | ||
//! of the algorithms are the same and there are useful lessons to learn! | ||
//! # Examples | ||
//! | ||
//! ``` | ||
//! use bst::functional::Tree; | ||
//! | ||
//! let tree = Tree::new(); | ||
//! | ||
//! // Nothing in here yet. | ||
//! assert_eq!(tree.find(&1), None); | ||
//! | ||
//! // This `insert` returns a new tree! | ||
//! let new_tree = tree.insert(1, 2); | ||
//! | ||
//! // The new tree has this new value but the old one doesn't. | ||
//! assert_eq!(new_tree.find(&1), Some(&2)); | ||
//! assert_eq!(tree.find(&1), None); | ||
//! | ||
//! // Insert a new value for the same key gives yet another tree. | ||
//! let newer_tree = new_tree.insert(1, 3); | ||
//! | ||
//! // And delete it for good measure. | ||
//! let newest_tree = newer_tree.delete(&1); | ||
//! | ||
//! // All history is preserved. | ||
//! assert_eq!(newest_tree.find(&1), None); | ||
//! assert_eq!(newer_tree.find(&1), Some(&3)); | ||
//! assert_eq!(new_tree.find(&1), Some(&2)); | ||
//! assert_eq!(tree.find(&1), None); | ||
//! ``` | ||
|
||
use std::cmp; | ||
use std::rc::Rc; | ||
|
||
/// A Binary Search Tree. This can be used for inserting, finding, | ||
/// and deleting keys and values. Note that this data structure is | ||
|
@@ -34,37 +61,46 @@ impl<K, V> Tree<K, V> { | |
} | ||
|
||
/// Returns a new tree that includes a node | ||
/// containing the given key and value | ||
/// containing the given key and value. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use bst::functional::Tree; | ||
/// | ||
/// let mut tree = Tree::new(); | ||
/// tree = tree.insert(1, 2); | ||
/// | ||
/// assert_eq!(tree.find(&1), Some(&2)); | ||
/// | ||
/// tree = tree.insert(1, 3); | ||
/// let tree = Tree::new(); | ||
/// let new_tree = tree.insert(1, 2); | ||
/// let newer_tree = new_tree.insert(1, 3); | ||
/// | ||
/// assert_eq!(tree.find(&1), Some(&3)); | ||
/// // All history is preserved. | ||
/// assert_eq!(newer_tree.find(&1), Some(&3)); | ||
/// assert_eq!(new_tree.find(&1), Some(&2)); | ||
/// assert_eq!(tree.find(&1), None); | ||
/// ``` | ||
pub fn insert(self, key: K, value: V) -> Self | ||
pub fn insert(&self, key: K, value: V) -> Self | ||
where | ||
K: cmp::Ord, | ||
{ | ||
match self { | ||
Tree::Leaf => Tree::Node(Node::new(key, value)), | ||
Tree::Node(n) => match key.cmp(&n.key) { | ||
cmp::Ordering::Less => Tree::Node(Node { | ||
left: Box::new(n.left.insert(key, value)), | ||
..n | ||
mlodato517 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
left: Rc::new(n.left.insert(key, value)), | ||
key: Rc::clone(&n.key), | ||
right: Rc::clone(&n.right), | ||
value: Rc::clone(&n.value), | ||
}), | ||
cmp::Ordering::Equal => Tree::Node(Node { | ||
value: Rc::new(value), | ||
key: Rc::clone(&n.key), | ||
left: Rc::clone(&n.left), | ||
right: Rc::clone(&n.right), | ||
}), | ||
cmp::Ordering::Equal => Tree::Node(Node { value, ..n }), | ||
cmp::Ordering::Greater => Tree::Node(Node { | ||
right: Box::new(n.right.insert(key, value)), | ||
..n | ||
right: Rc::new(n.right.insert(key, value)), | ||
key: Rc::clone(&n.key), | ||
left: Rc::clone(&n.left), | ||
value: Rc::clone(&n.value), | ||
}), | ||
}, | ||
} | ||
|
@@ -79,8 +115,8 @@ impl<K, V> Tree<K, V> { | |
/// ``` | ||
/// use bst::functional::Tree; | ||
/// | ||
/// let mut tree = Tree::new(); | ||
/// tree = tree.insert(1, 2); | ||
/// let tree = Tree::new(); | ||
/// let tree = tree.insert(1, 2); | ||
/// | ||
/// assert_eq!(tree.find(&1), Some(&2)); | ||
/// assert_eq!(tree.find(&42), None); | ||
|
@@ -109,86 +145,117 @@ impl<K, V> Tree<K, V> { | |
/// ``` | ||
/// use bst::functional::Tree; | ||
/// | ||
/// let mut tree = Tree::new(); | ||
/// tree = tree.insert(1, 2); | ||
/// | ||
/// tree = tree.delete(&1); | ||
/// let tree = Tree::new(); | ||
/// let tree = tree.insert(1, 2); | ||
/// let newer_tree = tree.delete(&1); | ||
/// | ||
/// assert_eq!(tree.find(&1), None); | ||
/// // All history is preserved. | ||
/// assert_eq!(newer_tree.find(&1), None); | ||
/// assert_eq!(tree.find(&1), Some(&2)); | ||
/// ``` | ||
pub fn delete(self, k: &K) -> Self | ||
pub fn delete(&self, k: &K) -> Self | ||
where | ||
K: cmp::Ord, | ||
{ | ||
match self { | ||
Tree::Leaf => self, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We now have to return an owned |
||
Tree::Leaf => Tree::Leaf, | ||
Tree::Node(n) => match k.cmp(&n.key) { | ||
cmp::Ordering::Less => Tree::Node(Node { | ||
left: Box::new(n.left.delete(k)), | ||
..n | ||
left: Rc::new(n.left.delete(k)), | ||
key: Rc::clone(&n.key), | ||
right: Rc::clone(&n.right), | ||
value: Rc::clone(&n.value), | ||
}), | ||
cmp::Ordering::Equal => match (*n.left, *n.right) { | ||
(Tree::Leaf, right_child) => right_child, | ||
(left_child, Tree::Leaf) => left_child, | ||
cmp::Ordering::Equal => match (n.left.as_ref(), n.right.as_ref()) { | ||
(Tree::Leaf, Tree::Leaf) => Tree::Leaf, | ||
(Tree::Leaf, Tree::Node(right)) => Tree::Node(right.clone()), | ||
(Tree::Node(left), Tree::Leaf) => Tree::Node(left.clone()), | ||
Comment on lines
+171
to
+172
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More just curious - are these 2 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct - |
||
|
||
// If we have two children we have to figure out | ||
// which node to promote. We choose here this node's | ||
// predecessor. That is, the largest node in this node's | ||
// left subtree. | ||
(Tree::Node(left_child), right_child) => { | ||
(Tree::Node(left_child), _) => { | ||
let (pred_key, pred_val, new_left) = left_child.delete_largest(); | ||
Tree::Node(Node { | ||
left: new_left, | ||
right: Box::new(right_child), // I really don't want this allocation here | ||
right: Rc::clone(&n.right), | ||
key: pred_key, | ||
value: pred_val, | ||
}) | ||
} | ||
}, | ||
cmp::Ordering::Greater => Tree::Node(Node { | ||
right: Box::new(n.right.delete(k)), | ||
..n | ||
right: Rc::new(n.right.delete(k)), | ||
key: Rc::clone(&n.key), | ||
left: Rc::clone(&n.left), | ||
value: Rc::clone(&n.value), | ||
}), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
/// A `Node` tree has a key that is used for searching/sorting and a value | ||
/// A `Node` has a key that is used for searching/sorting and a value | ||
/// that is associated with that key. It always has two children although | ||
/// those children may be [`Leaf`][Tree::Leaf]s. | ||
pub struct Node<K, V> { | ||
key: K, | ||
value: V, | ||
left: Box<Tree<K, V>>, | ||
right: Box<Tree<K, V>>, | ||
key: Rc<K>, | ||
value: Rc<V>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm conflicted here. I have this here because of how Going to think on it more but I'm also guessing one of Chris's patented Good Questions™️ will clear this up presently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still going to wait for Chris's wisdom but I'm semi-convinced this is correct (reference counting all the fields of the |
||
left: Rc<Tree<K, V>>, | ||
right: Rc<Tree<K, V>>, | ||
} | ||
|
||
/// Manual implementation of `Clone` so we don't clone references when the generic parameters | ||
/// aren't `Clone` themselves. | ||
/// | ||
/// Note the comment on generic structs in | ||
/// [the docs][<https://doc.rust-lang.org/std/clone/trait.Clone.html#derivable>]. | ||
impl<K, V> Clone for Node<K, V> { | ||
fn clone(&self) -> Self { | ||
Self { | ||
key: Rc::clone(&self.key), | ||
left: Rc::clone(&self.left), | ||
right: Rc::clone(&self.right), | ||
value: Rc::clone(&self.value), | ||
} | ||
} | ||
} | ||
|
||
impl<K, V> Node<K, V> { | ||
/// Construct a new `Node` with the given `key` and `value. | ||
fn new(key: K, value: V) -> Self { | ||
Self { | ||
key, | ||
value, | ||
left: Box::new(Tree::Leaf), | ||
right: Box::new(Tree::Leaf), | ||
key: Rc::new(key), | ||
value: Rc::new(value), | ||
left: Rc::new(Tree::Leaf), | ||
right: Rc::new(Tree::Leaf), | ||
} | ||
} | ||
|
||
/// Returns the largest node and a new subtree | ||
/// without that largest node. | ||
fn delete_largest(self) -> (K, V, Box<Tree<K, V>>) | ||
/// Returns the key and value of the largest node and a new subtree without that largest node. | ||
fn delete_largest(&self) -> (Rc<K>, Rc<V>, Rc<Tree<K, V>>) | ||
where | ||
K: cmp::Ord, | ||
{ | ||
match *self.right { | ||
Tree::Leaf => (self.key, self.value, self.left), | ||
match self.right.as_ref() { | ||
Tree::Leaf => ( | ||
Rc::clone(&self.key), | ||
Rc::clone(&self.value), | ||
Rc::clone(&self.left), | ||
), | ||
Tree::Node(r) => { | ||
let (key, value, sub) = r.delete_largest(); | ||
|
||
( | ||
key, | ||
value, | ||
Box::new(Tree::Node(Node { right: sub, ..self })), | ||
Rc::new(Tree::Node(Node { | ||
right: sub, | ||
key: Rc::clone(&self.key), | ||
left: Rc::clone(&self.left), | ||
value: Rc::clone(&self.value), | ||
})), | ||
) | ||
} | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.
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 is sort of duplicative with other doctests but it makes for nice docs.