-
-
Save pervognsen/2d48ef9757ee3fd579179239febc817e to your computer and use it in GitHub Desktop.
enum { BMAX = 32, BMIN = BMAX / 2, BHEIGHT = 6 }; | |
struct BNode { | |
uint32_t length; | |
Key keys[BMAX]; | |
union { | |
BNode *children[BMAX]; | |
Value values[BMAX]; | |
}; | |
}; | |
static void BNode_Initialize(BNode *node, uint32_t length, Key *keys, void *children) { | |
node->length = length; | |
CopyMemory(node->keys, keys, length * sizeof(Key)); | |
CopyMemory(node->children, children, length * sizeof(BNode *)); | |
} | |
static BNode *BNode_Create(uint32_t length, Key *keys, void *children) { | |
BNode *node = (BNode *)Allocate(sizeof(BNode)); | |
BNode_Initialize(node, length, keys, children); | |
return node; | |
} | |
static void BNode_Destroy(BNode *node, uint32_t height) { | |
for (uint32_t index = 0; index < node->length; index++) { | |
if (height > 1) { | |
BNode_Destroy(node->children[index], height - 1); | |
} | |
Free(node->children[index]); | |
} | |
} | |
static INLINE Key BNode_GetMaxKey(BNode *node) { | |
Assert(node->length > 0); | |
return node->keys[node->length - 1]; | |
} | |
static BNode *BNodeLeaf_Insert(BNode *leaf, Key key, Value value) { | |
uint32_t index = SearchKeys(leaf->keys, leaf->length, key); | |
if (index < leaf->length && leaf->keys[index] == key) { | |
leaf->values[index] = value; | |
return 0; | |
} | |
BNode *new_sibling = 0; | |
if (leaf->length == BMAX) { | |
new_sibling = BNode_Create(BMIN, leaf->keys + BMIN, leaf->values + BMIN); | |
leaf->length = BMIN; | |
if (index >= BMIN) { | |
leaf = new_sibling; | |
index -= BMIN; | |
} | |
} | |
Array_Insert(leaf->keys, leaf->length, index, key); | |
Array_Insert(leaf->values, leaf->length, index, value); | |
leaf->length++; | |
return new_sibling; | |
} | |
static BNode *BNode_Insert(BNode *node, Key key, Value value, uint32_t height) { | |
Assert(height > 0); | |
Assert(node->length > 0); | |
uint32_t index = SearchKeys(node->keys, node->length, key); | |
if (index == node->length) { | |
index--; | |
node->keys[index] = key; | |
} | |
BNode *new_child; | |
if (height == 1) { | |
new_child = BNodeLeaf_Insert(node->children[index], key, value); | |
} else { | |
new_child = BNode_Insert(node->children[index], key, value, height - 1); | |
} | |
BNode *new_sibling = 0; | |
if (new_child) { | |
if (node->length == BMAX) { | |
new_sibling = BNode_Create(BMIN, node->keys + BMIN, node->children + BMIN); | |
node->length = BMIN; | |
if (index >= BMIN) { | |
node = new_sibling; | |
index -= BMIN; | |
} | |
} | |
node->keys[index] = BNode_GetMaxKey(node->children[index]); | |
Array_Insert(node->keys, node->length, index + 1, BNode_GetMaxKey(new_child)); | |
Array_Insert(node->children, node->length, index + 1, new_child); | |
node->length++; | |
} | |
return new_sibling; | |
} | |
static bool BNodeLeaf_Delete(BNode *leaf, Key key) { | |
uint32_t index = SearchKeys(leaf->keys, leaf->length, key); | |
if (index < leaf->length && leaf->keys[index] == key) { | |
Array_Delete(leaf->keys, leaf->length, index); | |
Array_Delete(leaf->values, leaf->length, index); | |
leaf->length--; | |
return leaf->length == 0; | |
} | |
return false; | |
} | |
static void BNode_Delete(BNode *node, Key key, uint32_t height) { | |
Assert(height > 0); | |
uint32_t index = SearchKeys(node->keys, node->length, key); | |
if (index < node->length) { | |
if (height == 1) { | |
if (BNodeLeaf_Delete(node->children[index], key) && node->length > 1) { | |
Free(node->children[index]); | |
Array_Delete(node->keys, node->length, index); | |
Array_Delete(node->children, node->length, index); | |
node->length--; | |
} | |
} else { | |
BNode_Delete(node->children[index], key, height - 1); | |
} | |
} | |
} | |
struct BTree { | |
uint32_t height; | |
BNode root; | |
}; | |
void BTree_Initialize(BTree *tree) { | |
Assert(BMAX == 2 * BMIN); | |
Assert(sizeof(BNode *) == sizeof(Value)); | |
tree->height = 0; | |
tree->root.length = 0; | |
} | |
void BTree_Destroy(BTree *tree) { | |
if (tree->height > 0) { | |
BNode_Destroy(&tree->root, tree->height); | |
} | |
} | |
Value *BTree_Find(BTree *tree, Key key) { | |
uint32_t height = tree->height; | |
BNode *node = &tree->root; | |
for (;;) { | |
uint32_t index = SearchKeys(node->keys, node->length, key); | |
if (index == node->length) { | |
return 0; | |
} | |
if (height == 0) { | |
return (node->keys[index] == key) ? (node->values + index) : 0; | |
} | |
height--; | |
node = node->children[index]; | |
} | |
} | |
void BTree_Insert(BTree *tree, Key key, Value value) { | |
BNode *root = &tree->root; | |
BNode *new_root_sibling; | |
if (tree->height == 0) { | |
new_root_sibling = BNodeLeaf_Insert(root, key, value); | |
} else { | |
new_root_sibling = BNode_Insert(root, key, value, tree->height); | |
} | |
if (new_root_sibling) { | |
BNode *old_root = BNode_Create(root->length, root->keys, root->children); | |
Key keys[2] = {BNode_GetMaxKey(old_root), BNode_GetMaxKey(new_root_sibling)}; | |
BNode *children[2] = {old_root, new_root_sibling}; | |
BNode_Initialize(root, 2, keys, children); | |
tree->height++; | |
} | |
} | |
void BTree_Delete(BTree *tree, Key key) { | |
if (tree->height == 0) { | |
BNodeLeaf_Delete(&tree->root, key); | |
} else { | |
BNode_Delete(&tree->root, key, tree->height); | |
} | |
} |
Where is the header file for this? keys in BNode doesn't compile without it...
I think the non-excerpt version is here: https://gist.github.com/pervognsen/e7883b3de183fcd601c1edf7f7e9508b. This Gist was just an excerpt showing that the core B-tree operations can be implemented in very few lines of code, unlike what you see in most libraries.
Anyway, I should make it very clear that no code I ever post as a Gist is intended as a "library" or as a drop-in implementation. It's an example implementation and in some cases I don't even pretend that the code is tested (though the B-tree code was pretty heavily stress tested but I'm not sure if that version is the one posted as the Gist). If you just want a drop-in B-tree library, you have plenty of options.
How will
BHEIGHT
be used?