Advertisement
Guest User

Untitled

a guest
Mar 22nd, 2019
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.26 KB | None | 0 0
  1. /**
  2. * @file btree.cpp
  3. * Implementation of a B-tree class which can be used as a generic dictionary
  4. * (insert-only). Designed to take advantage of caching to be faster than
  5. * standard balanced binary search trees.
  6. */
  7.  
  8. /**
  9. * Finds the value associated with a given key.
  10. * @param key The key to look up.
  11. * @return The value (if found), the default V if not.
  12. */
  13. template <class K, class V>
  14. V BTree<K, V>::find(const K& key) const
  15. {
  16. return root == nullptr ? V() : find(root, key);
  17. }
  18.  
  19. /**
  20. * Private recursive version of the find function.
  21. * @param subroot A reference of a pointer to the current BTreeNode.
  22. * @param key The key we are looking up.
  23. * @return The value (if found), the default V if not.
  24. */
  25. template <class K, class V>
  26. V BTree<K, V>::find(const BTreeNode* subroot, const K& key) const
  27. {
  28. /* TODO Finish this function */
  29.  
  30. size_t first_larger_idx = insertion_idx(subroot->elements, key);
  31. if(first_larger_idx < subroot->elements.size() && first_larger_idx >=0){
  32. if(subroot->elements[first_larger_idx]== key)
  33. return subroot->elements[first_larger_idx].value;
  34. }
  35. else if(subroot->is_leaf)
  36. return V();
  37. else
  38. return find(subroot->children[first_larger_idx], key);
  39.  
  40. /* If first_larger_idx is a valid index and the key there is the key we
  41. * are looking for, we are done. */
  42.  
  43. /* Otherwise, we need to figure out which child to explore. For this we
  44. * can actually just use first_larger_idx directly. E.g.
  45. * | 1 | 5 | 7 | 8 |
  46. * Suppose we are looking for 6. first_larger_idx is 2. This means we want to
  47. * explore the child between 5 and 7. The children vector has a pointer for
  48. * each of the horizontal bars. The index of the horizontal bar we want is
  49. * 2, which is conveniently the same as first_larger_idx. If the subroot is
  50. * a leaf and we didn't find the key in it, then we have failed to find it
  51. * anywhere in the tree and return the default V.
  52. */
  53.  
  54. return V();
  55. }
  56.  
  57. /**
  58. * Inserts a key and value into the BTree. If the key is already in the
  59. * tree do nothing.
  60. * @param key The key to insert.
  61. * @param value The value to insert.
  62. */
  63. template <class K, class V>
  64. void BTree<K, V>::insert(const K& key, const V& value)
  65. {
  66. /* Make the root node if the tree is empty. */
  67. if (root == nullptr) {
  68. root = new BTreeNode(true, order);
  69. }
  70. insert(root, DataPair(key, value));
  71. /* Increase height by one by tossing up one element from the old
  72. * root node. */
  73. if (root->elements.size() >= order) {
  74. BTreeNode* new_root = new BTreeNode(false, order);
  75. new_root->children.push_back(root);
  76. split_child(new_root, 0);
  77. root = new_root;
  78. }
  79. }
  80.  
  81. /**
  82. * Splits a child node of a BTreeNode. Called if the child became too
  83. * large.
  84. * @param parent The parent whose child we are trying to split.
  85. * @param child_idx The index of the child in its parent's children
  86. * vector.
  87. */
  88. template <class K, class V>
  89. void BTree<K, V>::split_child(BTreeNode* parent, size_t child_idx)
  90. {
  91. /* Assume we are splitting the 3 6 8 child.
  92. * We want the following to happen.
  93. * | 2 |
  94. * / \
  95. * | 1 | | 3 | 6 | 8 |
  96. *
  97. *
  98. * Insert a pointer into parent's children which will point to the
  99. * new right node. The new right node is empty at this point.
  100. * | 2 | |
  101. * / \
  102. * | 1 | | 3 | 6 | 8 |
  103. *
  104. * Insert the mid element from the child into its new position in the
  105. * parent's elements. At this point the median is still in the child.
  106. * | 2 | 6 |
  107. * / \
  108. * | 1 | | 3 | 6 | 8 |
  109. *
  110. * Now we want to copy over the elements (and children) to the right
  111. * of the child median into the new right node, and make sure the left
  112. * node only has the elements (and children) to the left of the child
  113. * median.
  114. * | 2 | 6 |
  115. * / / \
  116. * | 1 | | 3 | | 8 |
  117. *
  118. */
  119.  
  120. /* The child we want to split. */
  121. BTreeNode* child = parent->children[child_idx];
  122. /* The "left" node is the old child, the right child is a new node. */
  123. BTreeNode* new_left = child;
  124. BTreeNode* new_right = new BTreeNode(child->is_leaf, order);
  125.  
  126. /* E.g.
  127. * | 3 | 6 | 8 |
  128. * Mid element is at index (3 - 1) / 2 = 1 .
  129. * Mid child (bar) is at index 4 / 2 = 2 .
  130. * E.g.
  131. * | 2 | 4 |
  132. * Mid element is at index (2 - 1) / 2 = 0 .
  133. * Mid child (bar) is at index 2 / 2 = 1 .
  134. * This definition is to make this BTree act like the visualization
  135. * at
  136. * https://www.cs.usfca.edu/~galles/visualization/BTree.html
  137. */
  138. size_t mid_elem_idx = (child->elements.size() - 1) / 2;
  139. size_t mid_child_idx = child->children.size() / 2;
  140.  
  141. /* Iterator for where we want to insert the new child. */
  142. auto child_itr = parent->children.begin() + child_idx + 1;
  143. /* Iterator for where we want to insert the new element. */
  144. auto elem_itr = parent->elements.begin() + child_idx;
  145. /* Iterator for the middle element. */
  146. auto mid_elem_itr = child->elements.begin() + mid_elem_idx;
  147. /* Iterator for the middle child. */
  148. auto mid_child_itr = child->children.begin() + mid_child_idx;
  149.  
  150.  
  151. /* TODO Your code goes here! */
  152. parent->elements.insert(elem_itr, child->elements[mid_elem_idx]);
  153. parent->children.insert(child_itr, new_right);
  154. new_right->elements.assign(mid_elem_itr + 1, child->elements.end());
  155. new_left->elements.erase(mid_elem_itr, child->elements.end());
  156. new_right->children.assign(mid_child_itr, child->children.end());
  157. new_left->children.erase(mid_child_itr, child->children.end());
  158.  
  159. }
  160.  
  161. /**
  162. * Private recursive version of the insert function.
  163. * @param subroot A reference of a pointer to the current BTreeNode.
  164. * @param pair The DataPair to be inserted.
  165. * Note: Original solution used std::lower_bound, but making the students
  166. * write an equivalent seemed more instructive.
  167. */
  168. template <class K, class V>
  169. void BTree<K, V>::insert(BTreeNode* subroot, const DataPair& pair)
  170. {
  171. /* There are two cases to consider.
  172. * If the subroot is a leaf node and the key doesn't exist subroot, we
  173. * should simply insert the pair into subroot.
  174. * Otherwise (subroot is not a leaf and the key doesn't exist in subroot)
  175. * we need to figure out which child to insert into and call insert on it.
  176. * After this call returns we need to check if the child became too large
  177. * and thus needs to be split to maintain order.
  178. */
  179.  
  180. size_t first_larger_idx = insertion_idx(subroot->elements, pair);
  181.  
  182. /* TODO Your code goes here! */
  183. if(subroot->is_leaf){
  184. if(first_larger_idx < subroot->elements.size())
  185. if(subroot->elements[first_larger_idx] == pair)
  186. return;
  187. subroot->elements.insert(subroot->elements.begin() + first_larger_idx, pair);
  188. return;
  189. }
  190. else if(first_larger_idx >= 0 && first_larger_idx <= subroot->elements.size()){
  191. if(subroot->elements[first_larger_idx] == pair)
  192. return;
  193. insert(subroot->children[first_larger_idx], pair);
  194. }
  195. if((unsigned int) subroot->children[first_larger_idx]->elements.size() >= this->order)
  196. split_child(subroot, first_larger_idx);
  197. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement