B树

B-Trees are version of 2-3 trees, which are self-balancing. They are used to improve Disk reads and have a complexity of O(log(n)), for every tree operations.The number of Childrens/Keys a particular node has, is determined by the Branching Factor/Degree of that tree. B-Trees will always have sorted keys.

  • Branching Factor(B) / Degree (D): If B = n, n <= Children per Node < 2(n), n-1 <= Keys per Node < 2(n) - 1

Properties

  • Worst/Average case performance for all operations O(log n)
  • Space complexity O(n)
  1. use std::convert::TryFrom;
  2. use std::fmt::Debug;
  3. use std::mem;
  4. struct Node<T> {
  5. keys: Vec<T>,
  6. children: Vec<Node<T>>,
  7. }
  8. pub struct BTree<T> {
  9. root: Node<T>,
  10. props: BTreeProps,
  11. }
  12. // Why to need a different Struct for props...
  13. // Check - http://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/#fnref:improvement
  14. struct BTreeProps {
  15. degree: usize,
  16. max_keys: usize,
  17. mid_key_index: usize,
  18. }
  19. impl<T> Node<T>
  20. where
  21. T: Ord,
  22. {
  23. fn new(degree: usize, _keys: Option<Vec<T>>, _children: Option<Vec<Node<T>>>) -> Self {
  24. Node {
  25. keys: match _keys {
  26. Some(_keys) => _keys,
  27. None => Vec::with_capacity(degree - 1),
  28. },
  29. children: match _children {
  30. Some(_children) => _children,
  31. None => Vec::with_capacity(degree),
  32. },
  33. }
  34. }
  35. fn is_leaf(&self) -> bool {
  36. self.children.is_empty()
  37. }
  38. }
  39. impl BTreeProps {
  40. fn new(degree: usize) -> Self {
  41. BTreeProps {
  42. degree,
  43. max_keys: degree - 1,
  44. mid_key_index: (degree - 1) / 2,
  45. }
  46. }
  47. fn is_maxed_out<T: Ord + Copy>(&self, node: &Node<T>) -> bool {
  48. node.keys.len() == self.max_keys
  49. }
  50. // Split Child expects the Child Node to be full
  51. /// Move the middle_key to parent node and split the child_node's
  52. /// keys/chilren_nodes into half
  53. fn split_child<T: Ord + Copy + Default>(&self, parent: &mut Node<T>, child_index: usize) {
  54. let child = &mut parent.children[child_index];
  55. let middle_key = child.keys[self.mid_key_index];
  56. let right_keys = match child.keys.split_off(self.mid_key_index).split_first() {
  57. Some((_first, _others)) => {
  58. // We don't need _first, as it will move to parent node.
  59. _others.to_vec()
  60. }
  61. None => Vec::with_capacity(self.max_keys),
  62. };
  63. let right_children = if !child.is_leaf() {
  64. Some(child.children.split_off(self.mid_key_index + 1))
  65. } else {
  66. None
  67. };
  68. let new_child_node: Node<T> = Node::new(self.degree, Some(right_keys), right_children);
  69. parent.keys.insert(child_index, middle_key);
  70. parent.children.insert(child_index + 1, new_child_node);
  71. }
  72. fn insert_non_full<T: Ord + Copy + Default>(&mut self, node: &mut Node<T>, key: T) {
  73. let mut index: isize = isize::try_from(node.keys.len()).ok().unwrap() - 1;
  74. while index >= 0 && node.keys[index as usize] >= key {
  75. index -= 1;
  76. }
  77. let mut u_index: usize = usize::try_from(index + 1).ok().unwrap();
  78. if node.is_leaf() {
  79. // Just insert it, as we know this method will be called only when node is not full
  80. node.keys.insert(u_index, key);
  81. } else {
  82. if self.is_maxed_out(&node.children[u_index]) {
  83. self.split_child(node, u_index);
  84. if node.keys[u_index] < key {
  85. u_index += 1;
  86. }
  87. }
  88. self.insert_non_full(&mut node.children[u_index], key);
  89. }
  90. }
  91. fn traverse_node<T: Ord + Debug>(&self, node: &Node<T>, depth: usize) {
  92. if node.is_leaf() {
  93. print!(" {0:{<1$}{2:?}{0:}<1$} ", "", depth, node.keys);
  94. } else {
  95. let _depth = depth + 1;
  96. for (index, key) in node.keys.iter().enumerate() {
  97. self.traverse_node(&node.children[index], _depth);
  98. // Check https://doc.rust-lang.org/std/fmt/index.html
  99. // And https://stackoverflow.com/a/35280799/2849127
  100. print!("{0:{<1$}{2:?}{0:}<1$}", "", depth, key);
  101. }
  102. self.traverse_node(node.children.last().unwrap(), _depth);
  103. }
  104. }
  105. }
  106. impl<T> BTree<T>
  107. where
  108. T: Ord + Copy + Debug + Default,
  109. {
  110. pub fn new(branch_factor: usize) -> Self {
  111. let degree = 2 * branch_factor;
  112. BTree {
  113. root: Node::new(degree, None, None),
  114. props: BTreeProps::new(degree),
  115. }
  116. }
  117. pub fn insert(&mut self, key: T) {
  118. if self.props.is_maxed_out(&self.root) {
  119. // Create an empty root and split the old root...
  120. let mut new_root = Node::new(self.props.degree, None, None);
  121. mem::swap(&mut new_root, &mut self.root);
  122. self.root.children.insert(0, new_root);
  123. self.props.split_child(&mut self.root, 0);
  124. }
  125. self.props.insert_non_full(&mut self.root, key);
  126. }
  127. pub fn traverse(&self) {
  128. self.props.traverse_node(&self.root, 0);
  129. println!();
  130. }
  131. pub fn search(&self, key: T) -> bool {
  132. let mut current_node = &self.root;
  133. let mut index: isize;
  134. loop {
  135. index = isize::try_from(current_node.keys.len()).ok().unwrap() - 1;
  136. while index >= 0 && current_node.keys[index as usize] > key {
  137. index -= 1;
  138. }
  139. let u_index: usize = usize::try_from(index + 1).ok().unwrap();
  140. if index >= 0 && current_node.keys[u_index - 1] == key {
  141. break true;
  142. } else if current_node.is_leaf() {
  143. break false;
  144. } else {
  145. current_node = &current_node.children[u_index];
  146. }
  147. }
  148. }
  149. }
  150. #[cfg(test)]
  151. mod test {
  152. use super::BTree;
  153. #[test]
  154. fn test_search() {
  155. let mut tree = BTree::new(2);
  156. tree.insert(10);
  157. tree.insert(20);
  158. tree.insert(30);
  159. tree.insert(5);
  160. tree.insert(6);
  161. tree.insert(7);
  162. tree.insert(11);
  163. tree.insert(12);
  164. tree.insert(15);
  165. assert!(tree.search(15));
  166. assert_eq!(tree.search(16), false);
  167. }
  168. }