Btrees are usually used for sets of data that are too large to fit into main memory and use on-disk memory. When the data needs to be stored on disk, the number of disk accesses need to be minimized.
For tree structures, a search requires access to data every time a new node is visited. That means that the deeper branches are, the more memory accesses are required. An M-tree is a like a binary tree, but instead of two children per node, it can have M children. This means, that in the same way binary trees have one key per node (2-1), M-trees have M-1 keys per node. Binary trees have in the best case log2 N average branch length, while M-trees have logM N. This cuts down the number of access to disk to memory.
An Mtree that is not balanced could degenerate into a Binary tree and lose its property of shorter branches. To avoid that, a Btree is basically a balanced Mtree, which means it is an Mtree where all leaves have the same height.
/****************************************************/
/* Using a Btree structure, read numbers from an */
/* input file and form a tree. All keys in the nodes*/
/* of the left subtree will be lower than parent key*/
/* and all keys in the right subtree are higher */
/* than the right subtree. Traverse the tree in */
/* order after each split. Print the input values */
/* and the output node key values in order to */
/* output files */
/* The display and */
/* traverse functions are designed recursively */
/* to simplify the design */
/****************************************************/
/* Preprocessor directives */
#include<stdio.h>
#include <stdlib.h>
#define M 5
#define FILENAME "input.txt"
#define FILEOUT "output.txt"
/* global variables */
struct node{
int n; /* number of keys in node */
int keys[M-1]; /* array of keys */
struct node *p[M]; /* pointers to children */
};
/* using enumeration for key status */
enum KeyStatus { Duplicate, SearchFailure, Success, InsertIt, LessKeys};
typedef struct node NODE;
NODE* root = NULL; /* defining tree's root as global */
FILE *fdout;
/* function prototypes */
void insert(int );
void display(NODE *, int, int);
enum KeyStatus insertHelper(NODE *, int , int *, NODE** );
int searchPos(int x, int *key_arr, int n);
void traverse(NODE *);
/* main function */
int main()
{
int key;
/* opening files */
printf("Opening files %s and %s.\n", FILENAME, FILEOUT);
FILE *fd = fopen(FILENAME, "r");
fdout = fopen(FILEOUT, "w");
if (fd == NULL || fdout == NULL)
{
perror("Could not open file");
return -1;
}
/* reading input sequence */
fscanf (fd, "%d, ", &key);
fprintf(fdout, "Adding the following elements to tree as read from file %s:\n\n", FILENAME);
while (fscanf (fd, "%d, ", &key) != EOF)
{
fprintf(fdout, "Adding key %d\n", key);
/* insert key */
insert(key);
fprintf(fdout, "Tree with new key:\n");
/* display tree */
display(root, 0, 0);
fprintf(fdout, "\n");
fprintf(fdout, "Traversing tree inorder:\n");
/* traverse tree inorder */
traverse(root);
fprintf(fdout, "\n\n");
}
close(fd);
close(fdout);
printf("Sequence has been read from %s, and output written to %s\n", FILENAME, FILEOUT);
return 0;
}/* end of main()*/
void insert(int key)
{
struct node *newnode;
int upKey;
enum KeyStatus value;
value = insertHelper(root, key, &upKey, &newnode); /* returns the key status, upkey, and newnode */
if (value == Duplicate)
fprintf(fdout, "Key is already in tree\n");
if (value == InsertIt)
{
struct node *uproot = root;
root=malloc(sizeof(struct node));
root->n = 1;
root->keys[0] = upKey;
root->p[0] = uproot;
root->p[1] = newnode;
}/* end of if */
}/* end of insert()*/
enum KeyStatus insertHelper(struct node *ptr, int key, int *upKey, struct node **newnode)
{
struct node *newPtr, *lastPtr;
int pos, i, n, splitPos;
int newKey, lastKey;
enum KeyStatus value;
/* inserting in root */
if (ptr == NULL)
{
*newnode = NULL;
*upKey = key;
return InsertIt;
}
n = ptr->n; /* number of keys in node */
pos = searchPos(key, ptr->keys, n); /* checking where to insert key in node */
/* key is duplicate */
if (pos < n && key == ptr->keys[pos])
return Duplicate;
value = insertHelper(ptr->p[pos], key, &newKey, &newPtr);
if (value != InsertIt)
return value;
/*If keys in node is less than M (number of keys in node)*/
if (n < M - 1)
{
pos = searchPos(newKey, ptr->keys, n);
/*Shifting the key and pointer right for inserting the new key*/
for (i=n; i>pos; i--)
{
ptr->keys[i] = ptr->keys[i-1];
ptr->p[i+1] = ptr->p[i];
}
/*Key is inserted at exact location*/
ptr->keys[pos] = newKey;
ptr->p[pos+1] = newPtr;
++ptr->n; /*incrementing the number of keys in node*/
return Success;
}
/* keys in node greater than M, so splitting is necessary */
/*If keys in nodes are maximum and position of node to be inserted is last*/
if (pos == M - 1)
{
lastKey = newKey;
lastPtr = newPtr;
}
else /*If keys in node are maximum and position of node to be inserted is not last*/
{
lastKey = ptr->keys[M-2];
lastPtr = ptr->p[M-1];
for (i=M-2; i>pos; i--)
{
ptr->keys[i] = ptr->keys[i-1];
ptr->p[i+1] = ptr->p[i];
}
ptr->keys[pos] = newKey;
ptr->p[pos+1] = newPtr;
}
splitPos = (M - 1)/2;
(*upKey) = ptr->keys[splitPos];
(*newnode)=malloc(sizeof(struct node));/* right node after split*/
ptr->n = splitPos; /* number of keys for left splitted node*/
(*newnode)->n = M-1-splitPos;/* number of keys for right splitted node*/
for (i=0; i < (*newnode)->n; i++)
{
(*newnode)->p[i] = ptr->p[i + splitPos + 1];
if(i < (*newnode)->n - 1)
(*newnode)->keys[i] = ptr->keys[i + splitPos + 1];
else
(*newnode)->keys[i] = lastKey;
}
(*newnode)->p[(*newnode)->n] = lastPtr;
fprintf(fdout, "Node has been splitted at key %d\n", ptr->keys[splitPos]);
return InsertIt;
}/* end of ins() */
void display(struct node *nodeptr, int blanks, int childno)
{
if (nodeptr)
{
int i;
for(i=1; i<=blanks; i++)
fprintf(fdout, " ");
if (childno != 0)
fprintf(fdout, "child node %d: ", childno);
else
fprintf(fdout, "root node: ");
for (i=0; i < nodeptr->n; i++)
fprintf(fdout, "%d ", nodeptr->keys[i]);
fprintf(fdout, "\n");
for (i=0; i <= nodeptr->n; i++)
display(nodeptr->p[i], blanks+5, i+1); /* display child */
}/* end of if */
}/* end of display() */
void traverse(struct node *nodeptr)
{
int i;
if (nodeptr)
{
for (i = 0; i < nodeptr->n; i++) // traverse keys and children in node
{
traverse(nodeptr->p[i]); // print left subtree from key position
fprintf(fdout, "%d, ", nodeptr->keys[i]); // print key
}
//i++; //for loop post-increments i, so i is incremented after leaving loop
traverse(nodeptr->p[i]); // there is one more child pointer than key
}
} /* end of traverse */
int searchPos(int key, int *key_arr, int n)
{
int pos=0;
while (pos < n && key > key_arr[pos])
pos++;
return pos;
}/*End of searchPos()*/
The input file for testing was this:
572, 430, 315, 363, 320, 545, 451, 437, 476, 472, 493, 395, 462, 521, 406, 412, 510, 560, 425, 595, 580, 583, 531, 511, 459, 518, 356, 379, 488, 532
The output generated was this:
Adding the following elements to tree as read from file input.txt:
Adding key 430
Tree with new key:
root node: 430
Traversing tree inorder:
430,
Adding key 315
Tree with new key:
root node: 315 430
Traversing tree inorder:
315, 430,
Adding key 363
Tree with new key:
root node: 315 363 430
Traversing tree inorder:
315, 363, 430,
Adding key 320
Tree with new key:
root node: 315 320 363 430
Traversing tree inorder:
315, 320, 363, 430,
Adding key 545
Node has been splitted at key 363
Tree with new key:
root node: 363
child node 1: 315 320
child node 2: 430 545
Traversing tree inorder:
315, 320, 363, 430, 545,
Adding key 451
Tree with new key:
root node: 363
child node 1: 315 320
child node 2: 430 451 545
Traversing tree inorder:
315, 320, 363, 430, 451, 545,
Adding key 437
Tree with new key:
root node: 363
child node 1: 315 320
child node 2: 430 437 451 545
Traversing tree inorder:
315, 320, 363, 430, 437, 451, 545,
Adding key 476
Node has been splitted at key 451
Tree with new key:
root node: 363 451
child node 1: 315 320
child node 2: 430 437
child node 3: 476 545
Traversing tree inorder:
315, 320, 363, 430, 437, 451, 476, 545,
Adding key 472
Tree with new key:
root node: 363 451
child node 1: 315 320
child node 2: 430 437
child node 3: 472 476 545
Traversing tree inorder:
315, 320, 363, 430, 437, 451, 472, 476, 545,
Adding key 493
Tree with new key:
root node: 363 451
child node 1: 315 320
child node 2: 430 437
child node 3: 472 476 493 545
Traversing tree inorder:
315, 320, 363, 430, 437, 451, 472, 476, 493, 545,
Adding key 395
Tree with new key:
root node: 363 451
child node 1: 315 320
child node 2: 395 430 437
child node 3: 472 476 493 545
Traversing tree inorder:
315, 320, 363, 395, 430, 437, 451, 472, 476, 493, 545,
Adding key 462
Node has been splitted at key 476
Tree with new key:
root node: 363 451 476
child node 1: 315 320
child node 2: 395 430 437
child node 3: 462 472
child node 4: 493 545
Traversing tree inorder:
315, 320, 363, 395, 430, 437, 451, 462, 472, 476, 493, 545,
Adding key 521
Tree with new key:
root node: 363 451 476
child node 1: 315 320
child node 2: 395 430 437
child node 3: 462 472
child node 4: 493 521 545
Traversing tree inorder:
315, 320, 363, 395, 430, 437, 451, 462, 472, 476, 493, 521, 545,
Adding key 406
Tree with new key:
root node: 363 451 476
child node 1: 315 320
child node 2: 395 406 430 437
child node 3: 462 472
child node 4: 493 521 545
Traversing tree inorder:
315, 320, 363, 395, 406, 430, 437, 451, 462, 472, 476, 493, 521, 545,
Adding key 412
Node has been splitted at key 412
Tree with new key:
root node: 363 412 451 476
child node 1: 315 320
child node 2: 395 406
child node 3: 430 437
child node 4: 462 472
child node 5: 493 521 545
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 430, 437, 451, 462, 472, 476, 493, 521, 545,
Adding key 510
Tree with new key:
root node: 363 412 451 476
child node 1: 315 320
child node 2: 395 406
child node 3: 430 437
child node 4: 462 472
child node 5: 493 510 521 545
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545,
Adding key 560
Node has been splitted at key 521
Node has been splitted at key 451
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 430 437
child node 2: 476 521
child node 1: 462 472
child node 2: 493 510
child node 3: 545 560
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545, 560,
Adding key 425
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521
child node 1: 462 472
child node 2: 493 510
child node 3: 545 560
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545, 560,
Adding key 595
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521
child node 1: 462 472
child node 2: 493 510
child node 3: 545 560 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545, 560, 595,
Adding key 580
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521
child node 1: 462 472
child node 2: 493 510
child node 3: 545 560 580 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545, 560, 580, 595,
Adding key 583
Node has been splitted at key 580
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 462 472
child node 2: 493 510
child node 3: 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 521, 545, 560, 580, 583, 595,
Adding key 531
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 462 472
child node 2: 493 510
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 521, 531, 545, 560, 580, 583, 595,
Adding key 511
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 462 472
child node 2: 493 510 511
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 462, 472, 476, 493, 510, 511, 521, 531, 545, 560, 580, 583, 595,
Adding key 459
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 459 462 472
child node 2: 493 510 511
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 493, 510, 511, 521, 531, 545, 560, 580, 583, 595,
Adding key 518
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 459 462 472
child node 2: 493 510 511 518
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 363, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 493, 510, 511, 518, 521, 531, 545, 560, 580, 583, 595,
Adding key 356
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320 356
child node 2: 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 459 462 472
child node 2: 493 510 511 518
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 356, 363, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 493, 510, 511, 518, 521, 531, 545, 560, 580, 583, 595,
Adding key 379
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320 356
child node 2: 379 395 406
child node 3: 425 430 437
child node 2: 476 521 580
child node 1: 459 462 472
child node 2: 493 510 511 518
child node 3: 531 545 560
child node 4: 583 595
Traversing tree inorder:
315, 320, 356, 363, 379, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 493, 510, 511, 518, 521, 531, 545, 560, 580, 583, 595,
Adding key 488
Node has been splitted at key 510
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320 356
child node 2: 379 395 406
child node 3: 425 430 437
child node 2: 476 510 521 580
child node 1: 459 462 472
child node 2: 488 493
child node 3: 511 518
child node 4: 531 545 560
child node 5: 583 595
Traversing tree inorder:
315, 320, 356, 363, 379, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 488, 493, 510, 511, 518, 521, 531, 545, 560, 580, 583, 595,
Adding key 532
Tree with new key:
root node: 451
child node 1: 363 412
child node 1: 315 320 356
child node 2: 379 395 406
child node 3: 425 430 437
child node 2: 476 510 521 580
child node 1: 459 462 472
child node 2: 488 493
child node 3: 511 518
child node 4: 531 532 545 560
child node 5: 583 595
Traversing tree inorder:
315, 320, 356, 363, 379, 395, 406, 412, 425, 430, 437, 451, 459, 462, 472, 476, 488, 493, 510, 511, 518, 521, 531, 532, 545, 560, 580, 583, 595,
References:
http://en.wikipedia.org/wiki/B-tree
yolinux.com/TUTORIALS/C++Enum.html
bluerwhite.org/btree/