move bst into separate module
This commit is contained in:
parent
bcf9a3db19
commit
64bf67e67d
2 changed files with 240 additions and 236 deletions
237
libtree/src/binary_search_tree.rs
Normal file
237
libtree/src/binary_search_tree.rs
Normal file
|
@ -0,0 +1,237 @@
|
|||
use core::fmt::Display;
|
||||
use crate::Stats;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BinarySearchTreeNode {
|
||||
pub key: u64,
|
||||
pub left: BST,
|
||||
pub right: BST,
|
||||
}
|
||||
|
||||
impl BinarySearchTreeNode {
|
||||
pub fn new(key: u64) -> Self {
|
||||
Self {
|
||||
key,
|
||||
left: BST(None),
|
||||
right: BST(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
match (&self.left.0, &self.right.0) {
|
||||
(None, None) =>
|
||||
1,
|
||||
(None, Some(right)) =>
|
||||
1 + right.height(),
|
||||
(Some(left), None) =>
|
||||
1 + left.height(),
|
||||
(Some(left), Some(right)) =>
|
||||
1 + (left.height()).max(right.height()),
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66661638
|
||||
fn replace_nth_char_ascii(s: &mut str, idx: usize, newchar: char) {
|
||||
let s_bytes: &mut [u8] = unsafe { s.as_bytes_mut() };
|
||||
assert!(idx < s_bytes.len());
|
||||
assert!(s_bytes[idx].is_ascii());
|
||||
assert!(newchar.is_ascii());
|
||||
// we've made sure this is safe.
|
||||
s_bytes[idx] = newchar as u8;
|
||||
}
|
||||
|
||||
fn _print(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, prefix: char, left_trace: &mut String, right_trace: &mut String) -> std::fmt::Result {
|
||||
if let Some(left) = &self.left.0 {
|
||||
left._print(f, depth + 1, '/', left_trace, right_trace)?;
|
||||
}
|
||||
if prefix == '/' {
|
||||
Self::replace_nth_char_ascii(left_trace, depth - 1, '|');
|
||||
}
|
||||
if prefix == '\\' {
|
||||
Self::replace_nth_char_ascii(right_trace, depth - 1, ' ');
|
||||
}
|
||||
if depth == 0 {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
if depth > 0 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
|
||||
|
||||
if depth > 0 {
|
||||
for i in 0..(depth - 1) {
|
||||
if left_trace.chars().nth(i).unwrap() == '|' || right_trace.chars().nth(i).unwrap() == '|' {
|
||||
write!(f, "| ")?;
|
||||
} else {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
write!(f, "{}-", prefix)?;
|
||||
}
|
||||
writeln!(f, "[{}]", self.key)?;
|
||||
Self::replace_nth_char_ascii(left_trace, depth, ' ');
|
||||
|
||||
if let Some(right) = &self.right.0 {
|
||||
Self::replace_nth_char_ascii(right_trace, depth, '|');
|
||||
right._print(f, depth + 1, '\\', left_trace, right_trace)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BST(Option<Box<BinarySearchTreeNode>>);
|
||||
|
||||
impl BST {
|
||||
pub fn insert(&mut self, key: u64) -> (bool, Stats) {
|
||||
let mut stats = Stats::new();
|
||||
|
||||
if self.0.is_none() {
|
||||
stats.writes += 1;
|
||||
self.0 = Some(Box::new(BinarySearchTreeNode::new(key)));
|
||||
return (true, stats);
|
||||
}
|
||||
|
||||
let mut current = self;
|
||||
while let Some(ref mut node) = current.0 {
|
||||
stats.reads += 1;
|
||||
use std::cmp::Ordering::*;
|
||||
stats.comparisons += 1;
|
||||
match node.key.cmp(&key) {
|
||||
Greater => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.left;
|
||||
},
|
||||
Less => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.right;
|
||||
},
|
||||
Equal => return (false, stats),
|
||||
}
|
||||
}
|
||||
|
||||
stats.writes += 1;
|
||||
current.0 = Some(Box::new(BinarySearchTreeNode::new(key)));
|
||||
|
||||
(true, stats)
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, key: u64) -> (bool, Stats) {
|
||||
let mut current: *mut BST = self;
|
||||
|
||||
let mut stats = Stats::default();
|
||||
|
||||
unsafe {
|
||||
while let Some(ref mut node) = (*current).0 {
|
||||
stats.reads += 1;
|
||||
use std::cmp::Ordering::*;
|
||||
stats.comparisons += 1;
|
||||
match node.key.cmp(&key) {
|
||||
Greater => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.left;
|
||||
},
|
||||
Less => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.right;
|
||||
},
|
||||
Equal => {
|
||||
match (node.left.0.as_mut(), node.right.0.as_mut()) {
|
||||
(None, None) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = None;
|
||||
},
|
||||
(None, Some(_)) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = node.right.0.take();
|
||||
},
|
||||
(Some(_), None) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = node.left.0.take();
|
||||
},
|
||||
(Some(_), Some(_)) => {
|
||||
(*current).0.as_mut().unwrap().key = {
|
||||
let mut to_return = None;
|
||||
|
||||
stats.reads += 1;
|
||||
if node.right.0.is_some() {
|
||||
stats.reads += 1;
|
||||
let mut current = &mut node.right;
|
||||
|
||||
stats.reads += 1;
|
||||
while current.0.as_ref().unwrap().left.0.is_some() {
|
||||
stats.writes += 1;
|
||||
current = &mut current.0.as_mut().unwrap().left;
|
||||
}
|
||||
|
||||
let node = current.0.take().unwrap();
|
||||
to_return = Some(node.key);
|
||||
stats.writes += 1;
|
||||
current.0 = node.right.0;
|
||||
}
|
||||
|
||||
to_return.unwrap()
|
||||
};
|
||||
},
|
||||
}
|
||||
return (true, stats);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(false, stats)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinarySearchTree {
|
||||
pub root: BST,
|
||||
pub size: usize,
|
||||
print_capacity: usize,
|
||||
pub stats: Stats,
|
||||
}
|
||||
|
||||
impl BinarySearchTree {
|
||||
pub fn new(print_capacity: usize) -> Self {
|
||||
Self {
|
||||
root: BST(None),
|
||||
size: 0,
|
||||
print_capacity,
|
||||
stats: Stats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
match &self.root.0 {
|
||||
Some(root) => root.height(),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: u64) -> bool {
|
||||
let (ret, stats) = self.root.insert(key);
|
||||
self.stats += stats;
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, key: u64) -> bool {
|
||||
let (ret, stats) = self.root.delete(key);
|
||||
self.stats += stats;
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn reset_stats(&mut self) {
|
||||
self.stats = Stats::default();
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BinarySearchTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.root.0 {
|
||||
Some(root) => root._print(f, 0, '-', &mut " ".repeat(self.print_capacity), &mut " ".repeat(self.print_capacity)),
|
||||
None => Ok(()),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
use std::fmt::Display;
|
||||
mod binary_search_tree;
|
||||
|
||||
pub use binary_search_tree::*;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Stats {
|
||||
|
@ -24,238 +26,3 @@ impl std::ops::AddAssign for Stats {
|
|||
self.writes += rhs.writes;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Node {
|
||||
pub key: u64,
|
||||
pub left: Tree,
|
||||
pub right: Tree,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
pub fn new(key: u64) -> Self {
|
||||
Self {
|
||||
key,
|
||||
left: Tree(None),
|
||||
right: Tree(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
match (&self.left.0, &self.right.0) {
|
||||
(None, None) =>
|
||||
1,
|
||||
(None, Some(right)) =>
|
||||
1 + right.height(),
|
||||
(Some(left), None) =>
|
||||
1 + left.height(),
|
||||
(Some(left), Some(right)) =>
|
||||
1 + (left.height()).max(right.height()),
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66661638
|
||||
fn replace_nth_char_ascii(s: &mut str, idx: usize, newchar: char) {
|
||||
let s_bytes: &mut [u8] = unsafe { s.as_bytes_mut() };
|
||||
assert!(idx < s_bytes.len());
|
||||
assert!(s_bytes[idx].is_ascii());
|
||||
assert!(newchar.is_ascii());
|
||||
// we've made sure this is safe.
|
||||
s_bytes[idx] = newchar as u8;
|
||||
}
|
||||
|
||||
fn _print(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, prefix: char, left_trace: &mut String, right_trace: &mut String) -> std::fmt::Result {
|
||||
if let Some(left) = &self.left.0 {
|
||||
left._print(f, depth + 1, '/', left_trace, right_trace)?;
|
||||
}
|
||||
if prefix == '/' {
|
||||
Self::replace_nth_char_ascii(left_trace, depth - 1, '|');
|
||||
}
|
||||
if prefix == '\\' {
|
||||
Self::replace_nth_char_ascii(right_trace, depth - 1, ' ');
|
||||
}
|
||||
if depth == 0 {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
if depth > 0 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
|
||||
|
||||
if depth > 0 {
|
||||
for i in 0..(depth - 1) {
|
||||
if left_trace.chars().nth(i).unwrap() == '|' || right_trace.chars().nth(i).unwrap() == '|' {
|
||||
write!(f, "| ")?;
|
||||
} else {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
write!(f, "{}-", prefix)?;
|
||||
}
|
||||
writeln!(f, "[{}]", self.key)?;
|
||||
Self::replace_nth_char_ascii(left_trace, depth, ' ');
|
||||
|
||||
if let Some(right) = &self.right.0 {
|
||||
Self::replace_nth_char_ascii(right_trace, depth, '|');
|
||||
right._print(f, depth + 1, '\\', left_trace, right_trace)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Tree(Option<Box<Node>>);
|
||||
|
||||
impl Tree {
|
||||
pub fn insert(&mut self, key: u64) -> (bool, Stats) {
|
||||
let mut stats = Stats::new();
|
||||
|
||||
if self.0.is_none() {
|
||||
stats.writes += 1;
|
||||
self.0 = Some(Box::new(Node::new(key)));
|
||||
return (true, stats);
|
||||
}
|
||||
|
||||
let mut current = self;
|
||||
while let Some(ref mut node) = current.0 {
|
||||
stats.reads += 1;
|
||||
use std::cmp::Ordering::*;
|
||||
stats.comparisons += 1;
|
||||
match node.key.cmp(&key) {
|
||||
Greater => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.left;
|
||||
},
|
||||
Less => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.right;
|
||||
},
|
||||
Equal => return (false, stats),
|
||||
}
|
||||
}
|
||||
|
||||
stats.writes += 1;
|
||||
current.0 = Some(Box::new(Node::new(key)));
|
||||
|
||||
(true, stats)
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, key: u64) -> (bool, Stats) {
|
||||
let mut current: *mut Tree = self;
|
||||
|
||||
let mut stats = Stats::default();
|
||||
|
||||
unsafe {
|
||||
while let Some(ref mut node) = (*current).0 {
|
||||
stats.reads += 1;
|
||||
use std::cmp::Ordering::*;
|
||||
stats.comparisons += 1;
|
||||
match node.key.cmp(&key) {
|
||||
Greater => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.left;
|
||||
},
|
||||
Less => {
|
||||
stats.reads += 1;
|
||||
current = &mut node.right;
|
||||
},
|
||||
Equal => {
|
||||
match (node.left.0.as_mut(), node.right.0.as_mut()) {
|
||||
(None, None) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = None;
|
||||
},
|
||||
(None, Some(_)) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = node.right.0.take();
|
||||
},
|
||||
(Some(_), None) => {
|
||||
stats.writes += 1;
|
||||
(*current).0 = node.left.0.take();
|
||||
},
|
||||
(Some(_), Some(_)) => {
|
||||
(*current).0.as_mut().unwrap().key = {
|
||||
let mut to_return = None;
|
||||
|
||||
stats.reads += 1;
|
||||
if node.right.0.is_some() {
|
||||
stats.reads += 1;
|
||||
let mut current = &mut node.right;
|
||||
|
||||
stats.reads += 1;
|
||||
while current.0.as_ref().unwrap().left.0.is_some() {
|
||||
stats.writes += 1;
|
||||
current = &mut current.0.as_mut().unwrap().left;
|
||||
}
|
||||
|
||||
let node = current.0.take().unwrap();
|
||||
to_return = Some(node.key);
|
||||
stats.writes += 1;
|
||||
current.0 = node.right.0;
|
||||
}
|
||||
|
||||
to_return.unwrap()
|
||||
};
|
||||
},
|
||||
}
|
||||
return (true, stats);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(false, stats)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinarySearchTree {
|
||||
pub root: Tree,
|
||||
pub size: usize,
|
||||
print_capacity: usize,
|
||||
pub stats: Stats,
|
||||
}
|
||||
|
||||
impl BinarySearchTree {
|
||||
pub fn new(print_capacity: usize) -> Self {
|
||||
Self {
|
||||
root: Tree(None),
|
||||
size: 0,
|
||||
print_capacity,
|
||||
stats: Stats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
match &self.root.0 {
|
||||
Some(root) => root.height(),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: u64) -> bool {
|
||||
let (ret, stats) = self.root.insert(key);
|
||||
self.stats += stats;
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, key: u64) -> bool {
|
||||
let (ret, stats) = self.root.delete(key);
|
||||
self.stats += stats;
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn reset_stats(&mut self) {
|
||||
self.stats = Stats::default();
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BinarySearchTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.root.0 {
|
||||
Some(root) => root._print(f, 0, '-', &mut " ".repeat(self.print_capacity), &mut " ".repeat(self.print_capacity)),
|
||||
None => Ok(()),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue