Following is my code in C for the implementation of B-Tree. The code works very strange sometimes as it gives 'Segmentation Fault' sometimes and if I run it again and provide the same input values, it works just fine.
It also happens that, I entered 1 value (e.g, 500) now this should be the root value, but the code also prints two empty (nil) child values.
And all this behavior is erratic, it does not happen every time. It almost never happens second time. I am sure, this has something to do with memory. Can someone suggest me a cure.
Thanks in advance !!
#include <stdio.h>
#include <stdlib.h>
#define ORDER 4
struct node{
int n;
int keys[ORDER-1];
struct node *children[ORDER];
};
struct toReturn{
int result;
struct node* nodeReturn;
};
struct node* splitNodeAndAdd(struct node* , int );
struct node* insertInTree(struct node* , int );
struct toReturn* insertRecursive(struct node *, int );
struct node* splitNodeAndAddNode(struct node* , struct node* );
struct node* addElement(struct node *, int);
void printTree(struct node*, int);
void addAndSort(int *, int, int);
int checkLeaf(struct node* node);
int main(){
int inputElement = 0;
printf("Enter the element you want to add. Press 0 to quit\n");
scanf("%d",&inputElement);
struct node * root;
root = (struct node*) malloc(sizeof(struct node));
while(inputElement != 0){
root = addElement(root,inputElement);
printTree(root,0);
scanf("%d",&inputElement);
}
return 0;
}
struct node* addElement(struct node * rootNode, int inputElement){
if(rootNode->n == 0){
rootNode->keys[0] = inputElement;
rootNode->n += 1;
return rootNode;
}
else{
rootNode = insertInTree(rootNode,inputElement);
return rootNode;
}
}
struct node* insertInTree(struct node* node, int inputElement){
if(checkLeaf(node) == 0){ //It is leaf node.
if(node->n == ORDER - 1){
struct node * temp = node;
struct node *newRoot = (struct node*) malloc(sizeof(struct node));
node = newRoot;
newRoot->children[0] = temp;
newRoot = splitNodeAndAdd(newRoot,inputElement);
return newRoot;
} else{
addAndSort(node->keys,node->n,inputElement);
node->n += 1;
}
} else{
//recursive add . DO IT.
struct toReturn * returnedValue = insertRecursive(node,inputElement);
node = returnedValue->nodeReturn;
}
return node;
}
//Change split node and add before running. Won't work otherwise.
struct toReturn* insertRecursive(struct node *node, int inputElement){
if(checkLeaf(node) == 0){
if(node->n == ORDER - 1){
struct node * temp = node;
struct node *newRoot = (struct node*) malloc(sizeof(struct node));
node = newRoot;
newRoot->children[0] = temp;
newRoot = splitNodeAndAdd(newRoot,inputElement);
struct toReturn *value = (struct toReturn*) malloc(sizeof(struct toReturn));
value->result = 0;
value->nodeReturn = newRoot;
return value; // Also send parameter to show its done.
} else{
addAndSort(node->keys,node->n,inputElement);
node->n += 1;
struct toReturn *value = (struct toReturn*) malloc(sizeof(struct toReturn));
value->result = 1;
value->nodeReturn = node;
return value; // Also send parameter to show its done.
}
}
else{
int i = node->n;
i -= 1;
while( i >= 0 && inputElement < node->keys[i]){
i -= 1;
}
i += 1;
//Go to child node of this using 'i'
struct toReturn* returnedValue = insertRecursive(node->children[i],inputElement);
if(returnedValue->result == 0){
//Now we have a node in returnedValue to be added to current node.
//Check if current root is also going to be full.
if(node->n == ORDER - 1){
struct node* currentNode = node;
struct node* nodeToAdd = returnedValue->nodeReturn;
struct node* newRoot = (struct node*) malloc(sizeof(struct node));
newRoot->children[0] = currentNode;
newRoot = splitNodeAndAddNode(newRoot,nodeToAdd);
struct toReturn* temp = (struct toReturn*) malloc(sizeof(struct toReturn));
temp->result = 0;
temp->nodeReturn = newRoot;// whatever is returned from splitNodeAndAddNode.
return temp;
} else{
int k = i;
for(k = node->n; k>i; k--){
node->keys[k] = node->keys[k-1];
}
for(k = node->n + 1; k > i; k--){
node->children[k] = node->children[k-1];
}
node->keys[i] = returnedValue->nodeReturn->keys[0];
node->n += 1;
node->children[i] = returnedValue->nodeReturn->children[0];
node->children[i+1] = returnedValue->nodeReturn->children[1];
returnedValue->result = 1;
returnedValue->nodeReturn = node;
}
}else{
node->children[i] = returnedValue->nodeReturn;
returnedValue->nodeReturn = node;
}
return returnedValue;
}
}
struct node* splitNodeAndAddNode(struct node* node, struct node* toAdd){
struct node* leftChild = node->children[0];
struct node* allChildren[ORDER+1];
int i = 0;
for(i = 0; i<ORDER; i++){
allChildren[i] = leftChild->children[i];
}
int childrenCount = 0;
int j = 0;
struct node* rightChild = (struct node*) malloc(sizeof(struct node));
int array[ORDER];
for(i=0; i<ORDER - 1; i++){
array[i] = leftChild->keys[i];
}
addAndSort(array,ORDER-1,toAdd->keys[0]);
int addedPosition = 0;
for(i=0; i<ORDER; i++){
if(array[i] == toAdd->keys[0]){
addedPosition = i;
}
}
for(j=ORDER-1; j>= addedPosition; j--){
allChildren[j+1] = allChildren[j];
}
allChildren[addedPosition] = toAdd->children[0];
allChildren[addedPosition+1] = toAdd->children[1];
int median = ORDER / 2;
node->keys[0] = array[median];
node->n += 1;
//add left and right child of node.
for(i = 0; i<median; i++){
leftChild->keys[i] = array[i];
leftChild->children[i] = allChildren[childrenCount];
childrenCount++;
}
leftChild->children[i] = allChildren[childrenCount];
childrenCount++;
leftChild->n = median;
for(i = median; i<ORDER-1; i++){
leftChild->keys[i] = 0;
}
int k = 0;
for(i = median+1; i<ORDER; i++){
rightChild->keys[k] = array[i];
rightChild->n += 1;
rightChild->children[k] = allChildren[childrenCount];
childrenCount++;
k++;
}
rightChild->children[k] = allChildren[childrenCount];
childrenCount++;
node->children[0] = leftChild;
node->children[1] = rightChild;
return node;
}
struct node* splitNodeAndAdd(struct node* rootNode, int inputElement){
struct node* leftChild = rootNode->children[0];
struct node* rightChild = (struct node*) malloc(sizeof(struct node));
int i = 0;
int j = 0;
int array[ORDER];
for(i =0; i<ORDER-1;i++){
array[i] = leftChild->keys[i];
}
addAndSort(array,ORDER-1,inputElement);
int medianIndex = 0;
for(i = 0; i<ORDER; i++){
if(inputElement == array[i]){
medianIndex = i;
break;
}
}
int median = ORDER / 2;
for(j=0; j<median; j++){
leftChild->keys[j] = array[j];
}
for(j=median; j<ORDER-1;j++){
leftChild->keys[j] = 0;
}
leftChild->n = median;
rootNode->keys[0] = array[median];
rootNode->n += 1;
int k = 0;
for(j= median+1; j<ORDER; j++){
rightChild->keys[k] = array[j];
rightChild->n += 1;
k++;
}
rootNode->children[0] = leftChild;
rootNode->children[1] = rightChild;
//Have to add all children if this is not leaf node.
//Have to change rootNode[0] to long term picture.
return rootNode;
}
void printTree(struct node *a, int level){
printf("%d : ",level);
for(int i=0; i<a->n; i++){
printf("%d ",a->keys[i]);
}
printf("\n");
if(checkLeaf(a) == 1){
for(int i=0; i <= a->n ; i++){
printTree(a->children[i],level+1);
}
}else {
return;
}
}
int checkLeaf(struct node* node){
int i = 0;
if(node->children[i] != NULL){
return 1;
}
return 0;
}
void addAndSort(int *array, int elementCount, int inputElement){
int i = 0;
for(i = elementCount-1; i >=0 && array[i] > inputElement; i--){ //else find the best
array[i+1] = array[i];
}
array[i+1] = inputElement;
}