12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019 |
- /*!
- Temelia - B-tree implementation source file.
- Copyright (C) 2008, 2009 Ceata (http://ceata.org/proiecte/temelia).
- @author Dascalu Laurentiu
- This program is free software; you can redistribute it and
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 3
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include "include/b_tree.h"
- #include "include/vector.h"
- #include <stdlib.h>
- /*
- * The source file contains, for the most important functions: search, insert
- * and delete; the pseudo code is taken from
- * http://cs-netlab-01.lynchburg.edu/courses/DataStII/BTreeOps.htm
- */
- struct _b_tree_t
- {
- /*! reference to root */
- b_tree_node_t root;
- /*! degree - maximum children number */
- int degree;
- int size;
- };
- struct _b_tree_node_t
- {
- /*! reference to parent */
- struct _b_tree_node_t *parent;
- /*! reference to children */
- vector_t children;
- /*! keys in current node */
- vector_t keys;
- };
- static b_tree_node_t _b_tree_new_node(int degree);
- static void _b_tree_delete(b_tree_node_t node);
- static void _b_tree_delete_node(b_tree_node_t node);
- static b_tree_node_t _b_tree_search(b_tree_node_t b_tree, void *key,
- int compare(void *x, void *y, void *context), void *context);
- static void _b_tree_divide(int degree, b_tree_node_t x, int index,
- b_tree_node_t y);
- static b_tree_node_t _b_tree_insert(b_tree_node_t root, void *key, int compare(
- void *x, void *y, void *context), void *context, int degree);
- static void _b_tree_show_indented(b_tree_node_t root, void key_handler(
- void *key, int level, void *fout), int level, void *fout);
- static void _b_tree_level_order(b_tree_node_t root, int level,
- void key_handler(void *x, void *fout), void *fout);
- static int _b_tree_get_height(b_tree_node_t node);
- static void
- *_b_tree_remove(b_tree_t b_tree, b_tree_node_t node, void *key, int compare(
- void *x, void *y, void *context), void *context, int degree);
- static INLINE void *_b_tree_node_find_predecesor(b_tree_node_t node);
- b_tree_t b_tree_new(int degree)
- {
- b_tree_t b_tree;
- /*
- * Allocate memory for a new B-tree, set it's root to NULL and degree
- * to the given value.
- */
- b_tree = (struct _b_tree_t *) _new(sizeof(struct _b_tree_t));
- b_tree->root = NULL;
- b_tree->degree = degree;
- b_tree->size = 0;
- return b_tree;
- }
- void b_tree_delete(b_tree_t b_tree)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER,);
- /*
- * If the root is not empty, then start deleting the root.
- * For this purpose, I created the function _b_tree_delete.
- */
- if (b_tree->root)
- _b_tree_delete(b_tree->root);
- /*
- * Set B-tree's root to NULL and degree to 0.
- */
- b_tree->root = NULL;
- b_tree->degree = 0;
- b_tree->size = 0;
- _delete(b_tree);
- }
- b_tree_node_t b_tree_get_root(b_tree_t b_tree)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- return b_tree->root;
- }
- int b_tree_get_degree(b_tree_t b_tree)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, -1);
- return b_tree->degree;
- }
- int b_tree_get_height(b_tree_t b_tree)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, -1);
- return _b_tree_get_height(b_tree->root);
- }
- int b_tree_node_get_depth(b_tree_node_t node)
- {
- int i = 0;
- _ASSERT(node, ==, NULL, NULL_POINTER, -1);
- /*
- * The algorithm is very simple and checks for a superior limit.
- * If i is too big, then it will become negative and the loop will be broken.
- * The result will be a negative number.
- */
- while ((node = node->parent) && ++i > 0)
- ;
- return i;
- }
- b_tree_node_t b_tree_node_get_parent(b_tree_node_t node)
- {
- _ASSERT(node, ==, NULL, NULL_POINTER, NULL);
- return node->parent;
- }
- int b_tree_node_get_children_number(b_tree_node_t node)
- {
- _ASSERT(node, ==, NULL, NULL_POINTER, -1);
- return vector_get_size(node->children);
- }
- b_tree_node_t b_tree_node_get_child(b_tree_node_t node, int index)
- {
- _ASSERT(node, ==, NULL, NULL_POINTER, NULL);
- return vector_get_key_at(node->children, index);
- }
- int b_tree_node_get_keys_number(b_tree_node_t node)
- {
- _ASSERT(node, ==, NULL, NULL_POINTER, -1);
- return vector_get_size(node->keys);
- }
- void *b_tree_node_get_key(b_tree_node_t node, int index)
- {
- _ASSERT(node, ==, NULL, NULL_POINTER, NULL);
- return vector_get_key_at(node->keys, index);
- }
- b_tree_node_t b_tree_search(b_tree_t b_tree, void *key, int compare(void *x,
- void *y, void *context), void *context)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(b_tree->size, <=, 0, INVALID_INPUT, NULL);
- /*
- * Search(btree, k)
- * //Search a B-tree, btree, for a key, k.
- * //if found k then return pointer to node containing k
- * //else return NULL
- *
- * current_node = root(btree)
- *
- * while current_node is not NULL
- * Search through keys in current_node until
- * 1. found k
- * 2. found first key (ki) larger than k or
- * 3. passed last key in current_node
- *
- * Case 1.
- * return pointer to current_node
- *
- * Case 2.
- * current_node = ith child of current_node
- *
- * Case 3.
- * current_node = last child of current_node
- * end while
- *
- * return NULL
- */
- return _b_tree_search(b_tree->root, key, compare, context);
- }
- b_tree_node_t b_tree_insert(b_tree_t b_tree, void *key, int compare(void *x,
- void *y, void *context), void *context, int add_if_exists)
- {
- b_tree_node_t root = NULL, add = NULL;
- int degree = 0;
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
- /*
- * B-Tree-Insert(void *, k)
- * //Insert the key, k, into tree, void *.
- * r = root[void *]
- * if the root is full (i.e., has 2t-1 keys) then
- * Allocate a new node and call it s. //s will be the new root.
- * root[void *] = s //make s the root. r still points to original root.
- * set the number of nodes in s to 0.
- * set the only child pointer of s (c1[s]) to point to r.
- * //r is now the child of s.
- * call B-Tree-Split-Child(s, 1, r) to split r and move its middle key up into s.
- * call B-Tree-Insert-NonFull(s, k) to insert the key, k, into the B-Tree
- * with root, s.
- * else //root is not full
- * call B-Tree-Insert-NonFull(r, k) to insert the key, k, into
- * the B-Tree with root, r.
- * end if
- *
- *
- * B-Tree-Insert-NonFull(x, k)
- * //Inserts the key, k, into a B-Tree. (k will ultimately be inserted into a leaf).
- * //Begin by attempting to insert k into nonfull node, x.
- * i = the number of keys in x.
- *
- * if x is a leaf then
- * since x is not full insert k into its proper place in x.
- * add one to the number of keys in x and update x on disk.
- * else //x is not a leaf
- * Move back from the last key of x until find child pointer to node
- * that is root of subtree in which k should be placed.
- *
- * if this child node is full then call B-Tree-Split-Child(x, i, ci[x])
- * //Note: we split full nodes on the way down the tree so that
- * // if a child of that node needs to be split its parent will
- * // be able to accept the middle key.
- * set i = index of whichever child of x is root of subtree in which
- * k should be placed.
- * call B-Tree-Insert-NonFull(ci[x], k) //Note: Recursive call
- * end if
- */
- root = b_tree->root;
- degree = b_tree->degree;
- if (root == NULL)
- {
- root = _b_tree_new_node(degree);
- vector_push_back(root->keys, key);
- b_tree->root = root;
- b_tree->size = 1;
- return root;
- }
- if (!add_if_exists && b_tree_search(b_tree, key, compare, context) != NULL)
- return NULL;
- b_tree->size++;
- if (vector_get_size(root->keys) == (2 * degree - 1))
- {
- add = _b_tree_new_node(degree);
- b_tree->root = add;
- root->parent = add;
- vector_push_back(add->children, root);
- _b_tree_divide(degree, add, 0, root);
- return _b_tree_insert(add, key, compare, context, degree);
- }
- return _b_tree_insert(root, key, compare, context, degree);
- }
- int b_tree_remove(b_tree_t b_tree, void *key, int compare(void *x, void *y,
- void *context), void *context)
- {
- int result;
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, -1);
- _ASSERT(compare, ==, NULL, NULL_POINTER, -1);
- _ASSERT(b_tree->size, <=, 0, INVALID_INPUT, -1);
- /*
- * The algorithm is : B-Tree-Delete(x, k)
- * k is the key to be deleted and
- * x is the root of the subtree from which k is to be deleted.
- * B-Tree-Delete returns true if it successfully deletes k else it returns false.
- *
- * if x is a leaf then
- * if k is in x then
- * delete k from x and return true
- * else return false //k is not in subtree
- *
- * else //x is an internal node
- * if k is in x then
- * y = the child of x that precedes k
- *
- * if y has at least t keys then
- * k' = the predecessor of k (use B-Tree-FindLargest)
- * Copy k' over k //i.e., replace k with k'
- * B-Tree-Delete(y, k') //Note: recursive call
- *
- * else //y has t-1 keys
- * z = the child of x that follows k
- *
- * if z has at least t keys then
- * k' = the successor of k
- * Copy k' over k //i.e., replace k with k'
- * B-Tree-Delete(z, k');
- *
- * else //both y and z have t-1 keys
- * merge k and all of z into y //y now contains 2t-1 keys.
- * //k and the pointer to z will be deleted from x.
- * B-Tree-Delete(y, k) //Note: recursive call
- *
- * else //k is not in internal node x.
- * ci[x] points to the root, c, of the subtree that could contain k.
- *
- * if c has t-1 keys then
- *
- * if c has an immediate left/right sibling, z, with t or more keys
- * then
- * Let k1 be the key in x that precedes/follows c.
- * Move k1 into c as the first/last key in c.
- * Let k2 be the last/first key in the immediate left/right
- * sibling, z.
- * Replace k1 in x with k2 from z (i.e., move k2 up into x).
- * Move the last/first child subtree of z to be the first/last
- * child subtree of c.
- *
- * else //c and both of its immediate siblings have t-1 keys.
- * //we cannot descend to a child node with only t-1 keys so
- * merge c with one of its immediate siblings and
- * make the appropriate key of x the middle key of the new node, c.
- * //Note: This may cause the root to collapse, thus making c the
- * new root.
- * B-Tree-Delete(c, k)
- */
- result = _b_tree_remove(b_tree, b_tree->root, key, compare, context,
- b_tree->degree) != NULL;
- if (result)
- b_tree->size--;
- return result;
- }
- b_tree_node_t b_tree_get_min(b_tree_t b_tree)
- {
- b_tree_node_t root = NULL;
- /*
- * The minimum node is the left-most node.
- * current_node = root;
- * while(current_node is not leaf)
- * current_node = first child of current_node;
- */
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(b_tree->root, ==, NULL, NULL_POINTER, NULL);
- root = b_tree->root;
- while (vector_get_size(root->children) > 0)
- root = vector_get_key_at(root->children, 0);
- return root;
- }
- void *b_tree_get_min_key(b_tree_t b_tree)
- {
- b_tree_node_t node = b_tree_get_min(b_tree);
- _ASSERT(node, ==, NULL, NULL_POINTER, NULL);
- /*
- * The minimum key is in the left-most node.
- * I find the left-most node, calling b_tree_get_min,
- * and then I return the first key contained by it.
- */
- return vector_get_key_at(node->keys, 0);
- }
- b_tree_node_t b_tree_get_max(b_tree_t b_tree)
- {
- b_tree_node_t root = NULL;
- /*
- * The maximum node is the right-most node.
- * current_node = root;
- * while(current_node is not leaf)
- * current_node = last child of current_node;
- */
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(b_tree->root, ==, NULL, NULL_POINTER, NULL);
- root = b_tree->root;
- while (vector_get_size(root->children) > 0)
- root = vector_get_key_at(root->children,
- vector_get_size(root->children) - 1);
- return root;
- }
- void *b_tree_get_max_key(b_tree_t b_tree)
- {
- b_tree_node_t node = b_tree_get_max(b_tree);
- _ASSERT(node, ==, NULL, NULL_POINTER, NULL);
- /*
- * The maximum key is in the right-most node.
- * I find the right-most node, calling b_tree_get_max,
- * and then I return the last key contained by it.
- */
- return vector_get_key_at(node->keys, vector_get_size(node->keys) - 1);
- }
- void b_tree_level_order(b_tree_t b_tree, void key_handler(void *x,
- void *context), void *context)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER,);
- _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
- _b_tree_level_order(b_tree->root, 0, key_handler, context);
- }
- void b_tree_show_indented(b_tree_t b_tree, void key_handler(void *key,
- int level, void *context), void *context)
- {
- _ASSERT(b_tree, ==, NULL, NULL_POINTER,);
- _ASSERT(b_tree->root, ==, NULL, NULL_POINTER,);
- _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
- _b_tree_show_indented(b_tree->root, key_handler, 0, context);
- }
- static b_tree_node_t _b_tree_new_node(int degree)
- {
- b_tree_node_t node;
- /*
- * An empty node has :
- * - NULL parent
- * - 2 * degree -1 maximum keys; initial 0 keys
- * - 2 * degree maximum children; initial 0 children
- */
- node = (struct _b_tree_node_t *) _new(sizeof(struct _b_tree_node_t));
- node->parent = NULL;
- node->keys = vector_new(2 * degree - 1);
- node->children = vector_new(2 * degree);
- return node;
- }
- static b_tree_node_t _b_tree_search(b_tree_node_t b_tree, void *key,
- int compare(void *x, void *y, void *context), void *context)
- {
- int i = 0, n = 0;
- _ASSERT(b_tree, ==, NULL, NULL_POINTER, NULL);
- n = vector_get_size(b_tree->keys);
- while (i < n && compare(key, vector_get_key_at(b_tree->keys, i), context)
- > 0)
- i++;
- if (i < n && compare(key, vector_get_key_at(b_tree->keys, i), context) == 0)
- return b_tree;
- if (vector_get_size(b_tree->children) == 0)
- return NULL;
- else
- return _b_tree_search(vector_get_key_at(b_tree->children, i), key,
- compare, context);
- }
- static void _b_tree_divide(int degree, b_tree_node_t x, int index,
- b_tree_node_t y)
- {
- int j;
- b_tree_node_t z;
- void *median = NULL;
- /*
- * //Splits a node, y, in a B-Tree and moves y's median key up to y's parent, x.
- * //y is the ith child of x.
- * //This function will only be called if y is full; i.e., has 2t-1 keys.
- *
- * 1. Allocate a new node and call it z. //z will be the new sibling of y.
- * 2. If y is a leaf then mark z as a leaf, else mark z as an internal node.
- * 3. set the number of keys in z to t-1
- * 4. copy the last t-1 keys of y into z.
- * 5. if z is not a leaf then copy the last t pointers of y into z.
- * 6. set the number of keys in y to t-1.
- * 7. insert a (child) pointer to node z into node x.
- * 8. insert the original middle key of node y up into node x, moving other keys
- * and pointers as necessary
- * 9. increment the number of keys in x by one.
- * 10. Update x, y and z on disk.
- */
- z = _b_tree_new_node(degree);
- // Divide keys
- for (j = 0; j < degree - 1; j++)
- vector_push_back(z->keys, vector_get_key_at(y->keys, j + degree));
- // Divide children references
- if (vector_get_size(y->children) > 0)
- for (j = 0; j < degree; j++)
- vector_push_back(z->children, vector_get_key_at(y->children, j
- + degree));
- median = vector_get_key_at(y->keys, degree - 1);
- vector_set_size(y->keys, degree - 1);
- if (vector_get_size(y->children) > degree)
- vector_set_size(y->children, degree);
- // Adjust the x, the parent of y and z
- vector_push_back(x->keys, NULL);
- for (j = vector_get_size(x->keys) - 2; j >= index; j--)
- vector_set_key_at(x->keys, j + 1, vector_get_key_at(x->keys, j));
- vector_set_key_at(x->keys, index, median);
- vector_push_after(x->children, z, y, compare_pointers, NULL);
- z->parent = x;
- }
- static b_tree_node_t _b_tree_insert(b_tree_node_t root, void *key, int compare(
- void *x, void *y, void *context), void *context, int degree)
- {
- int i = vector_get_size(root->keys);
- b_tree_node_t child = NULL;
- if (vector_get_size(root->children) == 0)
- {
- // I'm in a leaf node.
- vector_push_back(root->keys, NULL);
- while (i > 0 && compare(key, vector_get_key_at(root->keys, i - 1),
- context) < 0)
- {
- vector_set_key_at(root->keys, i, vector_get_key_at(root->keys, i
- - 1));
- i--;
- }
- vector_set_key_at(root->keys, i, key);
- return root;
- }
- else
- {
- // I may use a binary search, but i don't think it's useful because
- // the degree of a b-tree is small, in general.
- while (i > 0 && compare(key, vector_get_key_at(root->keys, i - 1),
- context) < 0)
- i--;
- child = vector_get_key_at(root->children, i);
- if (vector_get_size(child->keys) == (2 * degree - 1))
- {
- _b_tree_divide(degree, root, i, child);
- if (compare(key, vector_get_key_at(root->keys, i), context) > 0)
- return _b_tree_insert(vector_get_key_at(root->children, i + 1),
- key, compare, context, degree);
- }
- return _b_tree_insert(child, key, compare, context, degree);
- }
- }
- static void _b_tree_delete(b_tree_node_t node)
- {
- int i = 0;
- /*
- * Free the memory occupied by the children then
- * free current node.
- */
- for (; i < vector_get_size(node->children); i++)
- _b_tree_delete(vector_get_key_at(node->children, i));
- vector_delete(node->keys);
- vector_delete(node->children);
- node->keys = node->children = NULL;
- node->parent = NULL;
- _delete(node);
- }
- static void _b_tree_delete_node(b_tree_node_t node)
- {
- /*
- * Deleting a node implies :
- * - deleting the keys's vector
- * - deleting the children's vector
- * - setting keys, children and parent to NULL
- */
- vector_delete(node->keys);
- vector_delete(node->children);
- node->keys = node->children = NULL;
- node->parent = NULL;
- _delete(node);
- }
- static void _b_tree_show_indented(b_tree_node_t root, void key_handler(
- void *key, int level, void *context), int level, void *context)
- {
- int i = 0, n = 0;
- if (root == NULL)
- return;
- n = vector_get_size(root->keys);
- LOGGER("[_b_tree_show_indented] node %p has %d keys and %d children\n",
- root, vector_get_size(root->keys), vector_get_size(root->children));
- /*
- * for index in 0 to keys_number
- * call _b_tree_show_indented for the current node (addressable by index)
- * call key_handler for the current key (addressable by index)
- * call _b_tree_show_indented for the last node
- */
- for (; i < n; i++)
- {
- if (vector_get_size(root->children) > i)
- _b_tree_show_indented(vector_get_key_at(root->children, i),
- key_handler, level + 1, context);
- key_handler(vector_get_key_at(root->keys, i), level, context);
- }
- if (vector_get_size(root->children) > i)
- _b_tree_show_indented(vector_get_key_at(root->children, i),
- key_handler, level + 1, context);
- }
- static void _b_tree_level_order(b_tree_node_t root, int level,
- void key_handler(void *x, void *context), void *context)
- {
- int i;
- for (i = 0; i < level; i++)
- LOGGER(" ");
- LOGGER("( ");
- for (i = 0; i < vector_get_size(root->keys); i++)
- {
- /*
- * Calls key_handler for each key in the current node.
- */
- key_handler(vector_get_key_at(root->keys, i), context);
- LOGGER(" ");
- }
- LOGGER(")\n");
- for (i = 0; i < vector_get_size(root->children); i++)
- /*
- * Calls _b_tree_level_order for each children of the current node.
- */
- _b_tree_level_order(vector_get_key_at(root->children, i), level + 1,
- key_handler, context);
- }
- static int _b_tree_get_height(b_tree_node_t node)
- {
- int i = 1, max_height = 0;
- _ASSERT(node, ==, NULL, NOT_EXCEPTION, 0);
- _ASSERT(vector_get_size(node->children), ==, 0, NOT_EXCEPTION, 1);
- /*
- * height(NULL) = 0
- * height(node) = 1 + MAX(child_node | child_node is a child of node)
- */
- max_height = _b_tree_get_height(vector_get_key_at(node->children, 0));
- for (; i < vector_get_size(node->children) - 1; i++)
- max_height = MAX(max_height, _b_tree_get_height(vector_get_key_at(
- node->children, i)));
- return 1 + max_height;
- }
- static INLINE void *_b_tree_node_find_predecesor(b_tree_node_t node)
- {
- /*
- * Move to the right-most node, starting from the current node
- * and then return the last key stored in it.
- */
- while (b_tree_node_get_children_number(node))
- node = vector_get_key_at(node->children,
- vector_get_size(node->children) - 1);
- return vector_get_key_at(node->keys, vector_get_size(node->keys) - 1);
- }
- static INLINE void *_b_tree_node_find_successor(b_tree_node_t node, void *key)
- {
- int i = vector_search(node->keys, key, compare_pointers, NULL);
- b_tree_node_t child = NULL;
- /*
- * If there is a key after current key, then return it,
- * else return the first key stored in the next node.
- */
- if (i < vector_get_size(node->keys) - 1)
- return vector_get_key_at(node->keys, i + 1);
- child = vector_get_key_at(node->children, i + 1);
- if (child)
- return vector_get_key_at(child->keys, 0);
- return NULL;
- }
- static void *_b_tree_remove(b_tree_t b_tree, b_tree_node_t node, void *key,
- int compare(void *x, void *y, void *context), void *context, int degree)
- {
- int i = 0, j = 0;
- b_tree_node_t child = NULL, left = NULL, right = NULL;
- void *new_key = NULL;
- if (b_tree_node_get_children_number(node) == 0)
- {
- LOGGER("[_b_tree_remove] on leaf node %p\n", node);
- // Current node is leaf
- i = vector_search(node->keys, key, compare, context);
- if (i == -1)
- return NULL;
- vector_remove_key_at(node->keys, i);
- return key;
- }
- else
- {
- // Current node is internal node
- i = vector_search(node->keys, key, compare, context);
- if (i != -1)
- {
- LOGGER(
- "[_b_tree_remove] key is in an internal node %p at position %d\n",
- node, i);
- // Key is in current node
- left = vector_get_key_at(node->children, i);
- right = vector_get_key_at(node->children, i + 1);
- LOGGER("[_b_tree_remove] left node %p, right node %p\n", left,
- right);
- if (left && vector_get_size(left->keys) >= degree)
- {
- LOGGER("[_b_tree_remove] left node %p has %d keys\n", node,
- vector_get_size(left->keys));
- new_key = _b_tree_node_find_predecesor(left);
- LOGGER("[_b_tree_remove] successor %p, keys %d, position %d\n",
- new_key, vector_get_size(node->keys), i);
- if (new_key)
- {
- vector_set_key_at(node->keys, i, new_key);
- return _b_tree_remove(b_tree, left, new_key, compare,
- context, degree);
- }
- }
- else if (right && vector_get_size(right->keys) >= degree)
- {
- LOGGER("[_b_tree_remove] right node %p has %d keys\n", node,
- vector_get_size(right->keys));
- new_key = _b_tree_node_find_successor(right, key);
- LOGGER("[_b_tree_remove] successor %p, keys %d, position %d\n",
- new_key, vector_get_size(node->keys), i);
- if (new_key)
- {
- vector_set_key_at(node->keys, i, new_key);
- return _b_tree_remove(b_tree, right, new_key, compare,
- context, degree);
- }
- }
- else
- {
- LOGGER(
- "[_b_tree_remove] merging left node %p and right node %p\n",
- left, right);
- _ASSERT(left, ==, NULL, NULL_POINTER, NULL);
- // Both nodes have degree keys, so I have to merge them.
- vector_push_back(left->keys, key);
- for (i = 0; right && i < vector_get_size(right->keys); i++)
- vector_push_back(left->keys, vector_get_key_at(right->keys,
- i));
- for (i = 0; right && i < vector_get_size(right->children); i++)
- vector_push_back(left->children, vector_get_key_at(
- right->children, i));
- if (right)
- {
- vector_remove_key(node->children, right, compare_pointers,
- NULL);
- _b_tree_delete_node(right);
- }
- vector_remove_key(node->keys, key, compare_pointers, NULL);
- return _b_tree_remove(b_tree, left, key, compare, context,
- degree);
- }
- }
- else
- {
- i = vector_get_size(node->keys);
- // Key isn't in current node
- while (i > 0 && compare(key, vector_get_key_at(node->keys, i - 1),
- context) < 0)
- i--;
- LOGGER("[_b_tree_remove] keys %d, children %d, position %d\n",
- vector_get_size(node->keys),
- vector_get_size(node->children), i);
- child = vector_get_key_at(node->children, i);
- if (child)
- LOGGER(
- "[_b_tree_remove] child %p at position %d and %d keys\n",
- child, i, vector_get_size(child->keys));
- else
- LOGGER("[_b_tree_remove] child %p at position %d\n", child, i);
- if (child && vector_get_size(child->keys) == degree - 1)
- {
- if (i > 0)
- left = vector_get_key_at(node->children, i - 1);
- else
- left = NULL;
- if (i < vector_get_size(node->children) - 1)
- right = vector_get_key_at(node->children, i + 1);
- else
- right = NULL;
- LOGGER(
- "[_b_tree_remove] left child %p, right child %p, degree %d\n",
- left, right, degree);
- if (left)
- LOGGER("[_b_tree_remove] left node has %d keys\n",
- vector_get_size(left->keys));
- if (right)
- LOGGER("[_b_tree_remove] right node has %d keys\n",
- vector_get_size(right->keys));
- if ((left && vector_get_size(left->keys) >= degree) || (right
- && vector_get_size(right->keys) >= degree))
- {
- if (left && vector_get_size(left->keys) >= degree)
- {
- if (vector_get_size(node->keys) > i - 1)
- {
- vector_push_front(child->keys, vector_get_key_at(
- node->keys, i - 1));
- vector_push_before(node->keys,
- vector_get_key_at(left->keys,
- vector_get_size(left->keys) - 1),
- vector_get_key_at(node->keys, i - 1),
- compare_pointers, NULL);
- vector_remove_key_at(node->keys, i);
- vector_remove_key_at(left->keys, vector_get_size(
- left->keys) - 1);
- }
- }
- if (right && vector_get_size(right->keys) >= degree)
- {
- if (vector_get_size(node->keys) > i)
- {
- vector_push_back(child->keys, vector_get_key_at(
- node->keys, i));
- vector_push_after(node->keys, vector_get_key_at(
- right->keys, 0), vector_get_key_at(
- node->keys, i), compare_pointers, NULL);
- vector_remove_key_at(node->keys, i);
- vector_remove_key_at(right->keys, 0);
- }
- }
- }
- else
- {
- if (left)
- {
- vector_push_front(child->keys, vector_get_key_at(
- node->keys, i - 1));
- vector_remove_key_at(node->children, i - 1);
- vector_remove_key_at(node->keys, i - 1);
- for (j = vector_get_size(left->keys) - 1; j >= 0; j--)
- vector_push_front(child->keys, vector_get_key_at(
- left->keys, j));
- for (j = vector_get_size(left->children) - 1; j >= 0; j--)
- {
- vector_push_front(child->children,
- vector_get_key_at(left->children, j));
- ((b_tree_node_t) vector_get_key_at(left->children,
- j))->parent = child;
- }
- _b_tree_delete_node(left);
- }
- else if (right)
- {
- vector_push_back(child->keys, vector_get_key_at(
- node->keys, i));
- vector_remove_key_at(node->children, i + 1);
- vector_remove_key_at(node->keys, i);
- for (j = 0; j < vector_get_size(right->keys); j++)
- vector_push_back(child->keys, vector_get_key_at(
- right->keys, j));
- for (j = 0; j < vector_get_size(right->children); j++)
- {
- vector_push_back(child->children,
- vector_get_key_at(right->children, j));
- ((b_tree_node_t) vector_get_key_at(right->children,
- j))->parent = child;
- }
- _b_tree_delete_node(right);
- }
- // The root may collapse
- if (vector_get_size(node->keys) == 0)
- {
- if (node == b_tree->root)
- {
- _b_tree_delete_node(b_tree->root);
- b_tree->root = child;
- child->parent = NULL;
- }
- else if (node->parent)
- {
- i = vector_search(node->parent->children, node,
- compare_pointers, NULL);
- vector_set_key_at(node->parent->children, i, child);
- child->parent = node->parent;
- }
- }
- }
- }
- if (child)
- return _b_tree_remove(b_tree, child, key, compare, context,
- degree);
- }
- }
- return NULL;
- }
- int b_tree_get_size(b_tree_t btree)
- {
- _ASSERT(btree, ==, NULL, NULL_POINTER, -1);
- LOGGER("[b_tree_get_size] b-tree %p with size %d\n", btree, btree->size);
- return btree->size;
- }
|