Mercurial > lbo > hg > btreex
view src/lib.rs @ 2:df21e58157f3
New tree model (recursive) working somewhat
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 05 Jul 2022 07:08:06 -0700 |
parents | 04b6ed18abf3 |
children | a94eac64aee8 |
line wrap: on
line source
use ptree::TreeBuilder; use std::cmp::Ordering; // Min. order: 3 const ORDER: usize = 4; #[derive(Debug)] struct Node<T> { entries: [Option<T>; ORDER - 1], children: [Option<usize>; ORDER], parent: Option<usize>, } impl<T: Ord> Node<T> { fn new(parent: Option<usize>) -> Node<T> { Node { entries: Default::default(), children: Default::default(), parent: parent, } } } #[derive(Debug)] struct BTree<T> { v: Vec<Node<T>>, root: usize, } impl<T: std::fmt::Debug + Ord> BTree<T> { fn new(initial_capacity: usize) -> BTree<T> { BTree { v: Vec::with_capacity(initial_capacity), root: 0, } } fn free(&self, node: usize) -> usize { self.v[node] .entries .iter() .map(|e| if e.is_some() { 0 } else { 1 }) .sum() } fn get(&self, node: usize, elem: usize) -> &Option<T> { &self.v[node].entries[elem] } fn get_mut(&mut self, node: usize, elem: usize) -> &mut Option<T> { &mut self.v[node].entries[elem] } fn get_child(&self, node: usize, child: usize) -> &Option<usize> { &self.v[node].children[child] } fn get_child_mut(&mut self, node: usize, child: usize) -> &mut Option<usize> { &mut self.v[node].children[child] } /// Insert a value into an existing node, preserving the order. /// Requires that at least one slot be free. fn insert_inline( &mut self, node: usize, value: T, left: Option<usize>, right: Option<usize>, ) -> usize { assert!(self.free(node) >= 1); let nodeix = node; let mut loc = ORDER - 2; let node = &mut self.v[node]; for i in 0..ORDER - 1 { if let Some(ref el) = node.entries[i] { if value.cmp(el) == Ordering::Less { // Found right location. Shift remaining elements. loc = i; break; } } else { loc = i; break; } } for i in 0..(ORDER - 2 - loc) { node.entries[ORDER - 2 - i] = node.entries[ORDER - 3 - i].take(); node.children[ORDER - 1 - i] = node.children[ORDER - 2 - i].take(); } node.entries[loc] = Some(value); node.children[loc] = left; node.children[loc + 1] = right; if let Some(left) = left { self.v[left].parent = Some(nodeix) } if let Some(right) = right { self.v[right].parent = Some(nodeix); } loc } /// Split a node, returning the IDs of the two new nodes and the pivot value. /// Parent pointers need to be updated by caller. fn split(&mut self, node: usize) -> (usize, T, usize) { assert!(self.free(node) <= 1); // `node` will become left node. let leftix = node; let rightix = self.v.len(); println!("Starting split: {:?}", self.v[node]); let mut right = Node::<T>::new(None); // Parent updated by caller! let pivotix = (ORDER - 1) / 2; let pivot = self.get_mut(node, pivotix).take(); // Pivot-left child remains in left node. for i in pivotix + 1..ORDER { right.children[i - pivotix - 1] = self.get_child_mut(leftix, i).take(); } // Make sure to move all children pointers! //right.children[ORDER - pivotix] = self.get_child_mut(leftix, ORDER - 1).take(); for i in pivotix + 1..ORDER - 1 { right.entries[i - pivotix - 1] = self.get_mut(leftix, i).take(); } self.v.push(right); println!( "Finishing split: left {:?} right {:?} pivot {:?}", self.v[leftix], self.v[rightix], pivot ); (leftix, pivot.unwrap(), rightix) } fn is_leaf(&self, node: usize) -> bool { self.v[node].children.iter().all(|c| c.is_none()) } fn update_right_child(&mut self, node: usize, ch: usize) { for i in 0..ORDER - 1 { if self.get(node, i).is_none() { if let Some(subch) = self.get_child(node, i) { self.update_right_child(*subch, ch); return; } else { *self.get_child_mut(node, i) = Some(ch); return; } } } // This means that even the last child slot was used so far. self.update_right_child(self.get_child(node, ORDER - 1).unwrap(), ch); } /// Insert & root splitting. fn insert(&mut self, value: T) -> bool { if let Some((l, pivot, r)) = self.insert_into(self.root, value) { // Split root println!("Splitting root with new children {}, {}", l, r); let mut newroot = Node::new(None); let rootix = self.v.len(); newroot.children[0] = Some(l); newroot.children[1] = Some(r); newroot.entries[0] = Some(pivot); self.v[l].parent = Some(rootix); self.v[r].parent = Some(rootix); self.root = rootix; self.v.push(newroot); true } else { true } } /// Insert value recursively. If a split occurs, returns (left, pivot, right) tuple. fn insert_into(&mut self, node: usize, value: T) -> Option<(usize, T, usize)> { // BTree initialized? if self.v.len() == 0 { println!("Initializing"); self.v.push(Node::new(None)); self.insert_inline(self.root, value, None, None); return None; } // Leaf node with free space? We are finished. if self.is_leaf(node) && self.free(node) >= 1 { println!("Leaf {} with free space", node); self.insert_inline(node, value, None, None); return None; } else if self.is_leaf(node) && self.free(node) < 1 { // Leaf node but needs to be split. let (l, pivot, r) = self.split(node); // Full leaf node? println!("Splitting leaf {} into {} {:?} {}", node, l, pivot, r); // Insert value into left or right subtree. match value.cmp(&pivot) { Ordering::Less => assert!(self.insert_into(l, value).is_none()), Ordering::Greater => assert!(self.insert_into(r, value).is_none()), _ => panic!("Attempting to insert duplicate element"), }; return Some((l, pivot, r)); } else { // Descend into node. println!("Scanning node {}", node); let mut split = None; // Find correct child. for i in 0..ORDER - 1 { if i < ORDER - 2 { if let Some(el) = self.get(node, i) { if value.cmp(el) == Ordering::Less { split = self.insert_into(self.get_child(node, i).unwrap(), value); break; } } else { if let Some(ch) = self.get_child(node, i) { split = self.insert_into(*ch, value); break; } panic!( "Internal node missing child? {} => {:?}", node, self.v[node] ); } } else { if let Some(ch) = self.get_child(node, i) { split = self.insert_into(*ch, value); break; } else { let (l, pivot, r) = self.split(node); // Insert value into left or right subtree. match value.cmp(&pivot) { Ordering::Less => assert!(self.insert_into(l, value).is_none()), Ordering::Greater => assert!(self.insert_into(r, value).is_none()), _ => panic!("Attempting to insert duplicate element"), }; return Some((l, pivot, r)); } } } println!("Split necessary? {:?}", split); // Merge split if one happened below us. if let Some((l, pivot, r)) = split { if self.free(node) >= 1 { // We can insert the split here. self.insert_inline(node, pivot, Some(l), Some(r)); return None; } else { // Split this node too. let (nl, npivot, nr) = self.split(node); match pivot.cmp(&npivot) { Ordering::Less => self.insert_inline(nl, pivot, Some(l), Some(r)), Ordering::Greater => self.insert_inline(nr, pivot, Some(l), Some(r)), _ => panic!("Attempting to insert duplicate element"), }; return Some((nl, npivot, nr)); } } else { return None; } } } } impl<T: std::fmt::Debug> BTree<T> { fn debug_print(&self) -> String { let mut t = TreeBuilder::new(format!("<{}>", self.root)); self.print_subtree(&mut t, self.root); let mut o: Vec<u8> = Vec::new(); ptree::write_tree(&t.build(), &mut o); String::from_utf8(o).unwrap() } fn print_subtree(&self, tb: &mut TreeBuilder, node: usize) { let node = &self.v[node]; for i in 0..ORDER { if let Some(ch) = node.children[i] { self.print_subtree(tb.begin_child(format!("<{}>", ch)), ch); tb.end_child(); } if i < ORDER - 1 { tb.add_empty_child(format!("{:?}", node.entries[i])); } } } } #[cfg(test)] mod tests { use super::BTree; #[test] fn basic_test() { let mut bt = BTree::<i32>::new(16); let ns = &[15, 2, 21, 35, 4, 62, 31, 27, 88, 1, 12, 45, 11, 16, 23]; for n in ns { bt.insert(*n); println!("Inserting {}", n); println!("root: {}", bt.root); println!("{}", bt.debug_print()); } for (i, e) in bt.v.iter().enumerate() { println!("{} {:?}", i, e); } } }