-1

I am currently trying to implement a program that evaluates the computing time of my RBT(red black tree):

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <limits.h>

#define RED 'R'
#define BLACK 'B'


typedef struct rbtNode{
    int key;
    char color; //this time i also added the color since its an rbt
    struct rbtNode *leftChild;
    struct rbtNode *rightChild;
    struct rbtNode *parent;
} rbtNode;

struct rbtNode T_Nil_rbtNode; //defining the T_Nil node
rbtNode* t_nil = &T_Nil_rbtNode; //using it as the sentinel

//function for creating a new node
struct rbtNode* newNodeRBT(int key){
    rbtNode *temp =(rbtNode*)malloc(sizeof(rbtNode));
    temp->key = key;
    temp->color = 'R';
    temp->leftChild = NULL;
    temp->rightChild = NULL;
    temp->parent = NULL;

    return temp;
}

//function for performing a left side rotation
void TreeLeftRotate(struct rbtNode* root, struct rbtNode* x){
    struct rbtNode* y = x->rightChild; //y is initialize
    x->rightChild = y->leftChild; //y's left subtree are turning into x's right subtree

    if(y->leftChild != t_nil){
        y->leftChild->parent = x; //y's left subtree's parent is x
    }

    y->parent = x->parent; //y's parent is x's parent

    if(x->parent == t_nil){
        root = y;
    }else if (x->parent != t_nil && x == x->parent->leftChild){
        x->parent->leftChild = y;
    }else{
        x->parent->rightChild = y;
    }
    y->leftChild = x; //x is turning into y's left subtree
    x->parent = y; //x's parent is y
}

//function for performing a right side rotation
void TreeRightRotate(struct rbtNode* root, struct rbtNode* y){
    struct rbtNode* x = y->leftChild; //x is initialize
    y->leftChild = x->rightChild; //x's right subtree is turning into y's left subtree

    if(x->rightChild != t_nil){
        x->rightChild->parent = y; //x's right subtree's parent is y
    }

    x->parent = y->parent; //x's parent is y's parent

    if(y->parent == t_nil){
        root = x;
    }else if (y->parent != t_nil && y == y->parent->rightChild){
        y->parent->rightChild = x;
    }else{
        y->parent->leftChild = x;
    }
    x->rightChild = y; //y is turning into x's right subtree
    y->parent = x; //y's parent is x
}

//function for implementing the fixup for the left side, this function is needed for performing the insert fixup
void RBTreeInsertFixUpLeft(struct rbtNode* root, struct rbtNode* z){
    struct rbtNode* y = z->parent->parent->rightChild; //y is initialize
    if(y->color == 'R'){
        z->parent->color = 'B';
        y->color = 'B';
        z->parent->parent->color = 'R';
        z = z->parent->parent;
    }else{
        if(z == z->parent->rightChild){
            z = z->parent;
            TreeLeftRotate(root,z);
        }
        z->parent->color = 'B';
        z->parent->parent->color = 'R';
        TreeRightRotate(root,z->parent->parent);
    }
}


//function for implementing the fixup for the right side, this function is needed for performing the insert fixup
void RBTreeInsertFixUpRight(struct rbtNode* root,struct rbtNode* z){
    struct rbtNode* y = z->parent->parent->leftChild; //y is initialize
    if(y->color == 'R'){
        z->parent->color = 'B';
        y->color = 'B';
        z->parent->parent->color = 'R';
        z = z->parent->parent;
    }else{
        if(z == z->parent->leftChild){
            z = z->parent;
            TreeRightRotate(root,z);
        }
        z->parent->color = 'B';
        z->parent->parent->color = 'R';
        TreeLeftRotate(root,z->parent->parent);
    }
}


//function for performing a fixup of the RBT (necessary for pergorming an insertion)
void RBTreeInsertFixup(struct rbtNode* root, struct rbtNode* z){
    while(z->parent->color == 'R'){
        if(z->parent == z->parent->parent->leftChild){
            RBTreeInsertFixUpLeft(root,z); //calling the function for the left side
        }else{
            RBTreeInsertFixUpRight(root,z); //calling the function for the right side
        }
    }
    root->color = 'B';
}



//Function for inserting a new key in the RBT
void RBTreeInsert(struct rbtNode* root, struct rbtNode* z){
    struct rbtNode* y = t_nil;
    struct rbtNode* x = root;

    while(x != t_nil){
        y = x;
        if(z->key <x->key){
            x = x->leftChild;
        }else{
            x = x->rightChild;
        }
    }
    z->parent = y;
    if(y == t_nil){
        root = z;
    }if(y != t_nil && z->key < y->key){
        y->leftChild = z;
    }if(y != t_nil && z->key >= y->key){
        y->rightChild = z;
    }

    z->leftChild = t_nil;
    z->rightChild = t_nil;
    z->color = 'R';
    RBTreeInsertFixup(root,z);
}

//Function for searching a key in the RBT
void RBTreeSearch(struct rbtNode* root, int k){
    if(root == t_nil || root->key == k){
        return;
    }
    if(k <= root->key){
        RBTreeSearch(root->leftChild,k);
        RBTreeSearch(root->rightChild,k);
    }
}

//Function for emptying a RBT
void RBTreeDeallocate(struct rbtNode *root){
    if(root == NULL){
        return;
    }
    RBTreeDeallocate(root->leftChild);
    RBTreeDeallocate(root->rightChild);
    free(root);
}

//Function which executes the Single Experiment in regards to the RBT
double SingleExperimentRBT(int max_keys,double max_search,int max_instances){
    double t_tot = 0;
    int i;
    int key;
    double search;

    for(i= 1; i<=max_instances;i++){
        clock_t start_t, end_t;

        srand(0);
        struct rbtNode* root = newNodeRBT(rand()); //initialize the root

        start_t = clock();
        for(key = 1; key <= max_keys;key++){
            RBTreeInsert(root,newNodeRBT(rand())); //inserting the keys
        }
        for(search = 1; search <= max_search; search++){
            RBTreeSearch(root,rand()); //searching the keys
        }
        end_t = clock();
        double t_elapsed = (double)(end_t - start_t); //calculating the time elapsed
        t_tot += t_elapsed;

        RBTreeDeallocate(root); //Emptying the RBT

    }
    return t_tot/max_keys;
}

int main(void){
    int min_keys = 100000;
    int max_keys = 1000000;
    int max_instances = 5;
    int percentage_search = 60;
    int keys;
    int seed = 0;
    //setting up the main parameters for the experiments

    for(keys = min_keys; keys <= max_keys; keys += 100000){
        srand(seed);
        double max_search = (double)keys * (double)percentage_search / 100.0;
        double max_delete = keys - max_search;

        double timeRBT = SingleExperimentRBT(keys,max_search,max_instances);
        printf("Number of keys: %d -- timeRBT: %f\n",keys,timeRBT);

        seed = seed + 1;
    }
}

For some reason, I do receive the segmentation fault message as soon as I launch it :( My hypothesis is that it happens whenever the program tries to enter in the function "SingleExperimentRBT".

Where and why does this happen?

starball
  • 20,030
  • 7
  • 43
  • 238
Topo1717
  • 1
  • 3
  • 1
    `"My hypothesis is that it happens whenever the program tries to enter in the function "SingleExperimentRBT"."` -- Have you tried running the program line by line in a [debugger](https://stackoverflow.com/q/25385173/12149471), in order to verify this hypothesis? – Andreas Wenzel Dec 04 '21 at 16:14
  • `root` in SingleExperimentRBT is never changed, so your rotations cannot be correct. – William Pursell Dec 04 '21 at 16:23
  • @WilliamPursell How can I fix that? Thank you for your help ! – Topo1717 Dec 04 '21 at 16:42
  • @AndreasWenzel I tried it and unfortunately I wasn't able to find the error – Topo1717 Dec 04 '21 at 16:44
  • @LucaGirotti You probably need to pass `&root` to the functions and update the function signatures and definitions accordingly. – William Pursell Dec 04 '21 at 17:01
  • Running the code in a debugger reveals that the segmentation fault occurs in the line `if(z->key key){`. If you look a the values of `z` and `x`, you will find that `x` has the value `NULL`. This bug occurs in the second `while` loop iteration, the first time the function `RBTreeInsert` is called. Therefore, this bug should be easy to find by running your code one line at a time in a debugger. For this reason, I strongly suggest that you learn to use a debugger. – Andreas Wenzel Dec 04 '21 at 17:26
  • @WilliamPursell I tried to do that and unfortunately it still doesn't work – Topo1717 Dec 04 '21 at 17:33
  • @AndreasWenzel Thank you for your help, I tried doing what you suggested, I also understand your point, however I besides that I really cannot find a way to fix that. – Topo1717 Dec 04 '21 at 17:34

1 Answers1

2

Your problem is in your RBTreeInsert function: specifially, inside the while (x != t_nil) loop you set x to either leftChild or rightChild, but in newNodeRBT these are defaulted to NULL, therefore the if (z->key < x->key) statement in your loop can potentially (and does) dereference a x when it is null. I don't know enough about your code to fix it for you, but maybe you want to set leftChild and rightChild to t_nil which seems to be the other value for null you use in your code?

You should get comfortable in using a debugger to step through your code; this is really easy to spot in a debugger but when your program just crashes it is really hard to pin down. If you are on linux or mac, then look into gdb which is a really powerful debugging tool. There is plenty of info online about how to use it, if you need then I will add some links. If you are on Windows, then Visual Studio contains comes with a debugger inbuilt.

Dominic Price
  • 1,111
  • 8
  • 19
  • Thank you very much Dominic, I tried using the gfb debugger however I wasn't successfull at finding my issue. I also tried what you recommended to do it and it also didn't work out, unfortunately :( – Topo1717 Dec 04 '21 at 16:54