Add unsafe recursive level order traversal

pull/3/head
sgoudham 3 years ago
parent e96bdbebbf
commit 3440901bb7
Signed by: hammy
GPG Key ID: 44E818FD5457EEA4

@ -120,10 +120,12 @@ pub trait BinarySearchTree<T: Ord> {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use bst_rs::IterativeBST; /// use bst_rs::{BinarySearchTree, IterativeBST};
/// ///
/// let mut bst = IterativeBST::new(); /// let mut bst = IterativeBST::new();
/// assert!(bst.is_empty())
fn new() -> Self; fn new() -> Self;
fn size(&self) -> usize; fn size(&self) -> usize;
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
fn is_not_empty(&self) -> bool; fn is_not_empty(&self) -> bool;
@ -1137,25 +1139,42 @@ impl<T: Ord> Node<T> {
elements elements
} }
fn recursive_consume_level_order_vec(mut root: HeapNode<T>, elements: &mut Vec<T>) { fn recursive_consume_level_order_vec(root: HeapNode<T>, elements: &mut Vec<T>) {
let height = Node::recursive_height(&root); let height = Node::recursive_height(&root);
for i in 1..=height { for i in 0..height {
Node::recursive_consume_current_level(&mut root, elements, i); // SAFETY: this is sound because dealloc_boxes ensures that the elements don't
// get dropped again
unsafe { Node::write_level_into_vec(&root, elements, i) };
} }
Node::dealloc_boxes(root);
} }
fn recursive_consume_current_level(root: &mut HeapNode<T>, elements: &mut Vec<T>, level: usize) { /// # Safety
if let Some(..) = root { ///
match level.cmp(&1) { /// The caller must ensure that the values contained in the heap are not dropped again.
Ordering::Less => {} ///
Ordering::Equal => elements.push(root.as_mut().unwrap().value), /// Otherwise this could lead to a double free.
Ordering::Greater => { unsafe fn write_level_into_vec(root: &HeapNode<T>, elements: &mut Vec<T>, level: usize) {
if let Some(node) = root { if let Some(node) = root {
Node::recursive_consume_current_level(&mut node.left, elements, level - 1); if level == 0 {
Node::recursive_consume_current_level(&mut node.right, elements, level - 1); // "move" the value without actually moving
let element = std::ptr::read(&node.value);
elements.push(element);
} else {
Node::write_level_into_vec(&node.left, elements, level - 1);
Node::write_level_into_vec(&node.right, elements, level - 1);
} }
} }
} }
fn dealloc_boxes(root: HeapNode<T>) {
if let Some(node) = root {
// move out of the box by de-referencing to drop it and destructure the `Node`
let Node { value, left, right } = *node;
// ensure that the value is not dropped again by forgetting it
std::mem::forget(value);
Node::dealloc_boxes(left);
Node::dealloc_boxes(right);
} }
} }
} }
Loading…
Cancel
Save