AVL tree/Rust
<lang rust> /// This implementation uses an addressable vector as the tree's store. /// It is possible to construct a mutable tree using Rc<RefCell<>>, /// but it adds some complexity. /// /// "Pointers" to nodes are indices into the vector store, and have /// trait Copy. /// /// The index of a node in the vector store should not be confused with its key. extern crate rand; extern crate term_painter;
use std::cmp::Ordering; use std::fmt::{Debug, Display, Formatter, Result};
use rand::distributions::Uniform; use rand::Rng; use term_painter::Color::*; use term_painter::ToStyle;
pub type NodePtr = Option<usize>;
- [derive(Debug, PartialEq, Clone, Copy)]
pub enum Side {
Left, Right, Up, Root,
}
- [derive(Debug, PartialEq, Clone, Copy)]
enum DisplayElement {
TrunkSpace, SpaceLeft, SpaceRight, SpaceSpace, Root,
}
impl DisplayElement {
fn string(&self) -> String { match *self { DisplayElement::TrunkSpace => " │ ".to_string(), DisplayElement::SpaceRight => " ┌───".to_string(), DisplayElement::SpaceLeft => " └───".to_string(), DisplayElement::SpaceSpace => " ".to_string(), DisplayElement::Root => "├──".to_string(), } }
}
/// Handedness of balanced insert and delete operations differs only by values encapsulated here. struct BalanceConstants {
bal_incr: i8, this_side: Side, that_side: Side, key_order: Ordering, // Ins only // These are used in the +1/-1 & -1/+1 deletion cases gcm1_child_adj: i8, // Del only, balance adjustment to child for b = -1 grandchild gcm1_parent_adj: i8, // Del only, balance adjustment to parent for b = -1 grandchild gcp1_child_adj: i8, // Del only, balance adjustment to child for b = 1 grandchild gcp1_parent_adj: i8, // Del only, balance adjustment to parent for b = 1 grandchild
}
const BALANCE_CONSTANTS_A: BalanceConstants = BalanceConstants {
bal_incr: -1, this_side: Side::Left, that_side: Side::Right, key_order: Ordering::Greater, gcm1_child_adj: 0, gcm1_parent_adj: 1, gcp1_child_adj: -1, gcp1_parent_adj: 0,
};
const BALANCE_CONSTANTS_B: BalanceConstants = BalanceConstants {
bal_incr: 1, this_side: Side::Right, that_side: Side::Left, key_order: Ordering::Less, gcm1_child_adj: 1, gcm1_parent_adj: 0, gcp1_child_adj: 0, gcp1_parent_adj: -1,
};
- [derive(Debug, Clone, Copy)]
pub struct Node<K, V> {
key: K, value: V, balance: i8, left: NodePtr, right: NodePtr, up: NodePtr,
}
- [derive(Debug)]
pub struct AVLTree<K, V> {
root: NodePtr, store: Vec<Node<K, V>>,
}
impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Default for AVLTree<K, V> {
fn default() -> Self { AVLTree::new() }
}
impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> AVLTree<K, V> {
pub fn get_node(&self, np: NodePtr) -> Node<K, V> { assert!(np.is_some()); self.store[np.unwrap()] }
pub fn get_balance(&self, np: NodePtr) -> i8 { assert!(np.is_some()); self.store[np.unwrap()].balance }
pub fn get_key(&self, np: NodePtr) -> K { assert!(np.is_some()); self.store[np.unwrap()].key }
pub fn get_value(&self, np: NodePtr) -> V { assert!(np.is_some()); self.store[np.unwrap()].value }
pub fn get_pointer(&self, np: NodePtr, side: Side) -> NodePtr { assert!(np.is_some()); self.store[np.unwrap()].get_ptr(side) }
pub fn set_balance(&mut self, np: NodePtr, bal: i8) { assert!(np.is_some()); self.store[np.unwrap()].balance = bal; }
pub fn set_key(&mut self, np: NodePtr, to: K) { assert!(np.is_some()); self.store[np.unwrap()].key = to; }
pub fn set_value(&mut self, np: NodePtr, to: V) { assert!(np.is_some()); self.store[np.unwrap()].value = to; }
pub fn set_pointer(&mut self, np: NodePtr, side: Side, to: NodePtr) { assert!(np.is_some()); self.store[np.unwrap()].set_ptr(side, to); }
pub fn increment_balance(&mut self, np: NodePtr, delta: i8) -> i8 { assert!(np.is_some()); self.store[np.unwrap()].balance += delta; self.store[np.unwrap()].balance }
pub fn new() -> Self { AVLTree { root: None, store: Vec::<Node<K, V>>::with_capacity(20_000), } }
/// Insert key-value pub fn insert(&mut self, k: K, v: V) -> Option<Node<K, V>> { let (n, _) = self.insert_node(Node::new(k, v)); n }
/// Insert Node struct pub fn insert_node(&mut self, mut n: Node<K, V>) -> (Option<Node<K, V>>, Side) { if self.root.is_none() { assert!(self.store.is_empty()); self.store.push(n); self.root = Some(0); return (Some(n), Side::Root); }
let mut p = self.root; // Possibly None let mut prev = p; let mut side = Side::Left; while p.is_some() { prev = p; match n.key.cmp(&self.get_key(p)) { Ordering::Less => { side = Side::Left; p = self.get_pointer(p, side); } Ordering::Greater => { side = Side::Right; p = self.get_pointer(p, side); } Ordering::Equal => { println!("Key exists"); return (None, side); } } } // Set child's pointer n.up = prev; // Stow the node self.store.push(n); // Set parent's pointer let ptr = Some(self.store.len() - 1); self.set_pointer(prev, side, ptr); (Some(n), side) }
/// Insert key-value and rebalance pub fn insert_bal(&mut self, k: K, v: V) -> Option<Node<K, V>> { self.insert_node_bal(Node::new(k, v)) }
/// Insert Node struct and rebalance pub fn insert_node_bal(&mut self, n: Node<K, V>) -> Option<Node<K, V>> { let (nins, side) = self.insert_node(n); if nins.is_none() || side == Side::Root { return nins; }
let mut p = nins.unwrap().up; let mut is_left = side == Side::Left;
while p.is_some() { let i_c = get_insertion_constants(is_left);
let b = self.increment_balance(p, i_c.bal_incr); if b == 0 { break; // No further adjustments necessary } else if b.abs() > 1 { let child_p = self.get_pointer(p, i_c.this_side); match self.get_balance(child_p) * b { 2 => { // -2/-1 & +2/+1 patterns self.single_rotation(i_c.this_side, p, child_p); self.set_balance(p, 0); self.set_balance(child_p, 0); break; } -2 => { // -2/+1 & +2/-1 patterns let grand_p = self.get_pointer(child_p, i_c.that_side); self.double_rotation(i_c.this_side, p, child_p, grand_p); if self.get_pointer(child_p, i_c.this_side).is_none() { // Degenerate case, no subtrees self.set_balance(child_p, 0); self.set_balance(p, 0); } else if n.key.cmp(&self.get_key(grand_p)) == i_c.key_order { self.set_balance(child_p, i_c.bal_incr); self.set_balance(p, 0); } else { self.set_balance(child_p, 0); self.set_balance(p, -i_c.bal_incr); } self.set_balance(grand_p, 0); break; } _ => unreachable!(), } }
let child_p = p; p = self.get_pointer(p, Side::Up); if p.is_some() { let left_p = self.get_pointer(p, Side::Left); is_left = left_p.is_some() && left_p == child_p; } }
nins }
/// Remove the node at index from the store and patch the hole in the vector, /// modifying pointers in the moved node's parents and children. fn remove_carefully(&mut self, p: NodePtr) { assert!(p.is_some()); let index = p.unwrap(); let old_index = self.store.len() - 1; self.store.swap_remove(index);
if index == old_index { // Nothing moved return; }
// Element -1 has moved into the spot _index_. The in-pointers that need modifying // belong to that element's parent and children.
// Fix child pointer in parent: let parent_p = self.get_pointer(p, Side::Up); if parent_p.is_some() { let l = self.get_pointer(parent_p, Side::Left); if l == Some(old_index) { self.set_pointer(parent_p, Side::Left, Some(index)); } else { self.set_pointer(parent_p, Side::Right, Some(index)); } }
// Fix parent pointers in children: let l = self.get_pointer(p, Side::Left); let r = self.get_pointer(p, Side::Right); if l.is_some() { self.set_pointer(l, Side::Up, Some(index)); } if r.is_some() { self.set_pointer(r, Side::Up, Some(index)); }
// Fix root if necessary if self.root == Some(old_index) { self.root = Some(index); } }
/// Uses delete-by-copy procedure if node with key k has two children. /// Returns (parent, side) tuple. pub fn delete(&mut self, k: K) -> (NodePtr, Side) { let mut p = self.root; let mut prev = None; let mut res = None; let mut side = Side::Root; while p.is_some() { match k.cmp(&self.get_key(p)) { Ordering::Equal => { break; } Ordering::Less => { prev = p; side = Side::Left; p = self.get_pointer(p, side); } Ordering::Greater => { prev = p; side = Side::Right; p = self.get_pointer(p, side); } } }
if p.is_none() { println!("Key {:?} not found", k); return (res, side); }
let n = self.get_node(p); // Is this a leaf? if n.is_leaf() { if n.key.cmp(&self.get_key(self.root)) == Ordering::Equal { self.root = None; assert_eq!(self.store.len(), 1); } else { self.set_pointer(prev, side, None); } self.remove_carefully(p); // The prev pointer is now stale res = if prev == Some(self.store.len()) { p } else { prev };
// Is this a one-child node? } else if n.left.is_none() || n.right.is_none() { let ch = if n.left.is_some() { n.left } else { n.right }; if n.key.cmp(&self.get_key(self.root)) == Ordering::Equal { self.set_pointer(ch, Side::Up, None); self.root = ch; } else { self.set_pointer(prev, side, ch); self.set_pointer(ch, Side::Up, prev); } self.remove_carefully(p); // The prev pointer is now stale res = if prev == Some(self.store.len()) { p } else { prev };
// Complicated case: two children, do delete-by-copy. Replace n with its first // predecessor (the mirror image using the first successor would work as well). } else { let mut tmp = n.left; let mut last = tmp; prev = self.get_pointer(tmp, Side::Up); while tmp.is_some() && self.get_pointer(last, Side::Right).is_some() { prev = self.get_pointer(tmp, Side::Up); last = tmp; tmp = self.get_pointer(tmp, Side::Right); } tmp = last; // Copy ... let the_key = self.get_key(tmp); let the_value = self.get_value(tmp); self.set_key(p, the_key); self.set_value(p, the_value);
let left_ptr = self.get_pointer(tmp, Side::Left); if prev == p { self.set_pointer(p, Side::Left, left_ptr); if left_ptr.is_some() { self.set_pointer(left_ptr, Side::Up, p); } side = Side::Left; } else { self.set_pointer(prev, Side::Right, left_ptr); if left_ptr.is_some() { self.set_pointer(left_ptr, Side::Up, prev); } side = Side::Right; }
self.remove_carefully(tmp); // The prev pointer is now stale res = if prev.unwrap() == self.store.len() { tmp } else { prev }; }
(res, side) }
/// Rebalance on delete pub fn delete_bal(&mut self, k: K) -> Option<Node<K, V>> { // slug: (pointer to parent of deleted node, side of deleted node) let slug = self.delete(k); let (pdel, side) = slug; if pdel.is_none() { return None; }; let ndel = self.get_node(pdel);
let mut p = pdel; let mut is_left = side == Side::Left;
// Rebalance and update balance factors. There are two different rotation sequences that // are the same within handedness, // and the +1/-1 / -1/+1 sequence has three possible balance adjustments // depending on the grandchild. while p.is_some() { let d_c = get_deletion_constants(is_left);
let b = self.increment_balance(p, d_c.bal_incr); if b.abs() == 1 { break; // No further adjustments necessary } else if b.abs() > 1 { let child_p = self.get_pointer(p, d_c.this_side); match self.get_balance(child_p) * b { 2 => { // +1/+1 & -1/-1 patterns self.single_rotation(d_c.this_side, p, child_p); self.set_balance(p, 0); p = self.get_pointer(p, Side::Up); self.set_balance(p, 0); } 0 => { // +1/0 & -1/0 patterns self.single_rotation(d_c.this_side, p, child_p); self.set_balance(p, d_c.bal_incr); p = self.get_pointer(p, Side::Up); self.set_balance(p, -d_c.bal_incr); break; // No height change } -2 => { // +1/-1/x & -1/+1/x patterns let grand_p = self.get_pointer(child_p, d_c.that_side); self.double_rotation(d_c.this_side, p, child_p, grand_p); // p is now one child, grand_p is the other, child_p is their parent match self.get_balance(grand_p) { -1 => { self.set_balance(p, d_c.gcm1_parent_adj); self.set_balance(child_p, d_c.gcm1_child_adj); } 0 => { self.set_balance(p, 0); self.set_balance(child_p, 0); } 1 => { self.set_balance(p, d_c.gcp1_parent_adj); self.set_balance(child_p, d_c.gcp1_child_adj); } _ => unreachable!(), } self.set_balance(grand_p, 0); p = self.get_pointer(p, Side::Up); } _ => unreachable!(), } }
let child_p = p; p = self.get_pointer(p, Side::Up); if p.is_some() { let left_p = self.get_pointer(p, Side::Left); is_left = left_p.is_some() && left_p == child_p; } }
Some(ndel) }
/// Returns node value pub fn lookup(&self, k: K) -> Option<V> { self.search(k).map(|n| n.value) }
/// Returns node (not pointer) pub fn search(&self, k: K) -> Option<Node<K, V>> { let mut p = self.root; let mut res = None;
while p.is_some() { match k.cmp(&self.get_key(p)) { Ordering::Less => { p = self.get_pointer(p, Side::Left); } Ordering::Greater => { p = self.get_pointer(p, Side::Right); } Ordering::Equal => { res = Some(self.get_node(p)); break; } } } res }
/// Do an in-order traversal, where a "visit" prints the row with that node in it. fn display(&self, p: NodePtr, side: Side, e: &[DisplayElement], f: &mut Formatter) { if p.is_none() { return; }
let mut elems = e.to_vec(); let node = self.get_node(p); let mut tail = DisplayElement::SpaceSpace; if node.up != self.root { // Direction switching, need trunk element to be printed for lines before that node // is visited. let new_elem = if side == Side::Left && node.right.is_some() { DisplayElement::TrunkSpace } else { DisplayElement::SpaceSpace }; elems.push(new_elem); } let hindex = elems.len() - 1; self.display(node.right, Side::Right, &elems, f);
if p == self.root { elems[hindex] = DisplayElement::Root; tail = DisplayElement::TrunkSpace; } else if side == Side::Right { // Right subtree finished elems[hindex] = DisplayElement::SpaceRight; // Prepare trunk element in case there is a left subtree tail = DisplayElement::TrunkSpace; } else // if side == Side::Left { elems[hindex] = DisplayElement::SpaceLeft; let parent_p = self.get_pointer(p, Side::Up); let gp_p = self.get_pointer(parent_p, Side::Up); if gp_p.is_some() && self.get_pointer(gp_p, Side::Right) == parent_p { // Direction switched, need trunk element starting with this node/line elems[hindex - 1] = DisplayElement::TrunkSpace; } }
// Visit node => print accumulated elements. Each node gets a line. { for e in elems.clone() { let _ = write!(f, "{}", e.string()); } let _ = write!( f, "{key:>width$} ", key = Green.bold().paint(node.key), width = 2 ); let _ = write!( f, "{value:>width$} ", value = Blue.bold().paint(format!("{:.*}", 2, node.value)), width = 4 ); let _ = write!( f, "{bal:<-width$}\n", bal = Red.bold().paint(node.balance), width = 2 );
elems[hindex] = tail; }
self.display(node.left, Side::Left, &elems, f); }
pub fn gather_balances(&self) -> (Vec<K>, Vec<i8>) { let mut keys = Vec::<K>::new(); let mut bals = Vec::<i8>::new();
self.gather_balances_impl(self.root, &mut keys, &mut bals); (keys, bals) }
fn gather_balances_impl(&self, p: NodePtr, k: &mut Vec<K>, b: &mut Vec<i8>) { if p.is_none() { return; } let r = self.get_pointer(p, Side::Right); self.gather_balances_impl(r, k, b); k.push(self.get_key(p)); b.push(self.get_balance(p)); let l = self.get_pointer(p, Side::Left); self.gather_balances_impl(l, k, b) }
pub fn compute_balances(&mut self, p: NodePtr) -> i8 { self.compute_balances_impl(p, 0) }
fn compute_balances_impl(&mut self, p: NodePtr, level: i8) -> i8 { if p.is_none() { return level - 1; } let r = self.get_pointer(p, Side::Right); let l = self.get_pointer(p, Side::Left); let rb = self.compute_balances_impl(r, level + 1); let lb = self.compute_balances_impl(l, level + 1); self.set_balance(p, rb - lb); std::cmp::max(rb, lb) }
/// P Q /// / \ => / \ /// h Q P h' fn rotate_left(&mut self, p: NodePtr, q: NodePtr) { assert!(p.is_some()); assert!(q.is_some()); let p_parent = self.get_pointer(p, Side::Up); // Take care of parent pointers self.set_pointer(q, Side::Up, p_parent); self.set_pointer(p, Side::Up, q); let ql = self.get_pointer(q, Side::Left); if ql.is_some() { self.set_pointer(ql, Side::Up, p); }
// Take care of child pointers self.set_pointer(q, Side::Left, p); self.set_pointer(p, Side::Right, ql); if p_parent.is_some() { let side = if self.get_pointer(p_parent, Side::Right) == p { Side::Right } else { Side::Left }; self.set_pointer(p_parent, side, q); } else { self.root = q; } }
/// P Q /// / \ => / \ /// Q h h' P fn rotate_right(&mut self, p: NodePtr, q: NodePtr) { assert!(p.is_some()); assert!(q.is_some()); let p_parent = self.get_pointer(p, Side::Up); // Take care of parent pointers self.set_pointer(q, Side::Up, p_parent); self.set_pointer(p, Side::Up, q); let qr = self.get_pointer(q, Side::Right); if qr.is_some() { self.set_pointer(qr, Side::Up, p); }
// Take care of child pointers self.set_pointer(q, Side::Right, p); self.set_pointer(p, Side::Left, qr); if p_parent.is_some() { let side = if self.get_pointer(p_parent, Side::Right) == p { Side::Right } else { Side::Left }; self.set_pointer(p_parent, side, q); } else { self.root = q; } }
fn single_rotation(&mut self, side: Side, p: NodePtr, q: NodePtr) { if side == Side::Left { self.rotate_right(p, q); } else { self.rotate_left(p, q); } }
fn double_rotation(&mut self, side: Side, p: NodePtr, child_p: NodePtr, grand_p: NodePtr) { if side == Side::Left { self.rotate_left(child_p, grand_p); self.rotate_right(p, grand_p); } else { self.rotate_right(child_p, grand_p); self.rotate_left(p, grand_p); } }
}
impl<K: Ord + Copy, V: Copy> Node<K, V> {
pub fn new(k: K, v: V) -> Node<K, V> { Node { key: k, value: v, balance: 0, left: None, right: None, up: None, } }
pub fn is_leaf(&self) -> bool { self.left.is_none() && self.right.is_none() }
pub fn set_ptr(&mut self, side: Side, to: NodePtr) { let field = match side { Side::Up => &mut self.up, Side::Left => &mut self.left, _ => &mut self.right, }; *field = to; }
pub fn get_ptr(&self, side: Side) -> NodePtr { match side { Side::Up => self.up, Side::Left => self.left, _ => self.right, } }
}
impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Display for AVLTree<K, V> {
fn fmt(&self, f: &mut Formatter) -> Result { if self.root.is_none() { write!(f, "[empty]") } else { let v: Vec<DisplayElement> = Vec::new(); self.display(self.root, Side::Up, &v, f); Ok(()) } }
}
fn get_insertion_constants(is_left: bool) -> &'static BalanceConstants {
if is_left { &BALANCE_CONSTANTS_A } else { &BALANCE_CONSTANTS_B }
}
fn get_deletion_constants(is_left: bool) -> &'static BalanceConstants {
get_insertion_constants(!is_left)
}
pub fn random_bal_tree(n: u32) -> AVLTree<i32, f32> {
let mut tree: AVLTree<i32, f32> = AVLTree::new(); let mut rng = rand::thread_rng(); // `Uniform` rather than `gen_range`'s `Uniform::sample_single` for speed let key_range = Uniform::new(-(n as i32) / 2, (n as i32) / 2); let value_range = Uniform::new(-1.0, 1.0); tree.insert_bal(0, rng.sample(value_range)); for _ in 0..n { tree.insert_bal(rng.sample(key_range), rng.sample(value_range)); } tree
}
- [cfg(test)]
mod tests {
use rand::{seq, thread_rng};
use super::AVLTree; use random_bal_tree;
#[test] fn test_insert() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert(0, 0.0); tree.insert(8, 8.8); tree.insert(-8, -8.8); assert!(tree.insert(4, 4.4).is_some()); tree.insert(12, 12.12);
assert_eq!(tree.lookup(4), Some(4.4)); assert_eq!(tree.lookup(5), None); assert_eq!(tree.lookup(-8), Some(-8.8));
let s = &tree.store; assert_eq!( s[s[s[tree.root.unwrap()].right.unwrap()].right.unwrap()].value, 12.12 ); assert_eq!( s[s[s[tree.root.unwrap()].right.unwrap()].right.unwrap()].left, None ); }
#[test] fn test_delete() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert(0, 0.0); tree.insert(8, 8.8); tree.insert(-8, -8.8); assert!(tree.insert(4, 4.4).is_some()); tree.insert(12, 12.12);
// delete leaf tree.delete(12); assert_eq!(tree.lookup(12), None); let mut n = tree.search(8).unwrap(); assert_eq!(n.right, None);
// delete one-child node tree.delete(4); assert_eq!(tree.lookup(4), None); n = tree.search(0).unwrap(); assert_eq!(tree.store[n.right.unwrap()].key, 8);
// delete two-child node tree.insert(6, 6.6); tree.insert(10, 10.10); tree.insert(7, 7.7); tree.delete(8); n = tree.search(7).unwrap(); assert_eq!(tree.store[n.left.unwrap()].key, 6); assert_eq!(tree.store[n.right.unwrap()].key, 10); assert_eq!(tree.store[n.up.unwrap()].key, 0);
// delete two-child root tree.delete(0); assert_eq!(tree.store[tree.root.unwrap()].key, -8);
// delete one-child root tree.delete(-8); assert_eq!(tree.store[tree.root.unwrap()].key, 7);
// delete no-child root tree.delete(6); tree.delete(7); tree.delete(10); assert!(tree.root.is_none()); assert_eq!(tree.store.len(), 0); }
#[test] fn test_rotate_left() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert(0, 0.0); tree.insert(8, 8.8); tree.insert(4, 4.4); tree.insert(-8, -8.8);
let mut r = tree.root; let mut right = tree.store[r.unwrap()].right; tree.rotate_left(r, right); r = tree.root; right = tree.store[r.unwrap()].right; let left = tree.store[r.unwrap()].left; let left_left = tree.store[left.unwrap()].left; let left_right = tree.store[left.unwrap()].right; assert_eq!(right, None); assert_eq!(tree.store[left.unwrap()].key, 0); assert_eq!(tree.store[left_left.unwrap()].key, -8); assert_eq!(tree.store[left_right.unwrap()].key, 4); assert_eq!(tree.store[r.unwrap()].key, 8); }
#[test] fn test_rotate_right() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert(0, 0.0); tree.insert(8, 8.8); tree.insert(-8, -8.8); tree.insert(-4, 4.4);
let mut r = tree.root; let mut left = tree.store[r.unwrap()].left; tree.rotate_right(r, left); r = tree.root; left = tree.store[r.unwrap()].left; let right = tree.store[r.unwrap()].right; let right_right = tree.store[right.unwrap()].right; let right_left = tree.store[right.unwrap()].left; assert_eq!(left, None); assert_eq!(tree.store[right.unwrap()].key, 0); assert_eq!(tree.store[right_right.unwrap()].key, 8); assert_eq!(tree.store[right_left.unwrap()].key, -4); assert_eq!(tree.store[r.unwrap()].key, -8); }
#[test] // This tree tests all four insertion types fn test_balanced_inserts() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert_bal(0, 0.0); tree.insert_bal(8, 8.8); tree.insert_bal(-8, -8.8); tree.insert_bal(12, 12.12); tree.insert_bal(16, 16.16); tree.insert_bal(11, 11.11); tree.insert_bal(4, 4.4); tree.insert_bal(-10, -8.8); tree.insert_bal(-12, -8.8); tree.insert_bal(-9, -8.8);
let mut res = tree.gather_balances(); let (_, bals) = res; assert!(bals.iter().max().unwrap() < &2); assert!(bals.iter().min().unwrap() > &-2);
for _ in 0..10 { tree = random_bal_tree(1000); res = tree.gather_balances(); let (_, bals) = res; assert!(bals.iter().max().unwrap() < &2); assert!(bals.iter().min().unwrap() > &-2); } }
#[test] /// This sequence hits all five rotation possibilities on each side. fn test_balanced_deletes() { let mut tree: AVLTree<i32, f32> = AVLTree::new(); tree.insert_bal(0, 0.0); tree.insert_bal(-32, 0.0); tree.insert_bal(32, 0.0); tree.insert_bal(-64, 0.0); tree.insert_bal(64, 0.0); tree.delete_bal(64); tree.delete_bal(32); tree.delete_bal(-32); tree.delete_bal(-64); tree.delete_bal(0); assert_eq!(tree.root, None); assert_eq!(tree.store.len(), 0);
tree.insert_bal(0, 0.0); tree.insert_bal(-32, 0.0); tree.insert_bal(32, 0.0); tree.insert_bal(-64, 0.0); tree.insert_bal(64, 0.0); tree.insert_bal(-16, 0.0); tree.insert_bal(16, 0.0); tree.insert_bal(-8, 0.0); tree.insert_bal(8, 0.0); tree.insert_bal(-12, 0.0); tree.insert_bal(-7, 0.0); tree.insert_bal(-6, 0.0); tree.insert_bal(-11, 0.0);
tree.delete_bal(-64); tree.delete_bal(-32); tree.delete_bal(-7); tree.delete_bal(-6); tree.delete_bal(-16); tree.delete_bal(-11); tree.delete_bal(-12); tree.delete_bal(8); tree.delete_bal(-8); tree.delete_bal(0); tree.insert_bal(24, 0.0); tree.insert_bal(8, 0.0); tree.insert_bal(4, 0.0); tree.insert_bal(128, 0.0); tree.insert_bal(48, 0.0); tree.delete_bal(32); tree.delete_bal(48);
tree.insert_bal(-24, 0.0); tree.insert_bal(-8, 0.0); tree.insert_bal(-128, 0.0); tree.insert_bal(-48, 0.0); tree.insert_bal(-20, 0.0); tree.insert_bal(-30, 0.0); tree.insert_bal(-22, 0.0); tree.insert_bal(-21, 0.0); tree.delete_bal(24); tree.delete_bal(64); tree.delete_bal(-30); tree.delete_bal(-22); tree.delete_bal(-21); tree.delete_bal(-128); tree.delete_bal(128); tree.delete_bal(-8); tree.insert_bal(-96, 0.0); tree.insert_bal(-95, 0.0); tree.insert_bal(-10, 0.0); tree.insert_bal(6, 0.0); tree.delete_bal(-24);
let mut res = tree.gather_balances(); let (_, bals) = res; assert!(bals.iter().max().unwrap() < &2); assert!(bals.iter().min().unwrap() > &-2);
let mut p = tree.root; while p.is_some() { let key = tree.store[p.unwrap()].key; tree.delete_bal(key); p = tree.root; } assert_eq!(tree.root, None); assert_eq!(tree.store.len(), 0);
// */*/+1 patterns tree.insert(6, 0.0); tree.insert(-1, 0.0); tree.insert(9, 0.0); tree.insert(7, 0.0); tree.insert(3, 0.0); tree.insert(-9, 0.0); tree.insert(4, 0.0); p = tree.root; tree.compute_balances(p); tree.delete_bal(-9); res = tree.gather_balances(); let (_, bals) = res; tree.compute_balances(p); res = tree.gather_balances(); let (_, bals_after) = res; assert_eq!(bals, bals_after);
tree.insert(6, 0.0); tree.insert(-1, 0.0); tree.insert(3, 0.0); tree.insert(9, 0.0); tree.insert(7, 0.0); tree.insert(11, 0.0); tree.insert(8, 0.0); p = tree.root; tree.compute_balances(p); tree.delete_bal(-1); res = tree.gather_balances(); let (_, bals) = res; tree.compute_balances(p); res = tree.gather_balances(); let (_, bals_after) = res; assert_eq!(bals, bals_after);
let mut rng = thread_rng(); for _ in 0..100 { tree = random_bal_tree(100); let sample = seq::sample_iter(&mut rng, -50..50, 80).unwrap(); for i in sample { tree.delete_bal(i); } }
res = tree.gather_balances(); let (_, bals) = res;
if bals.len() > 0 { assert!(*bals.iter().max().unwrap() < 2); assert!(*bals.iter().min().unwrap() > -2); }
return; }
} </lang>