I was trying to implement Red Black Tree but was unable to code it myself so I was searching for it's code written in C and found the below code on github I analyzed it and it was pretty straight forward and simple so I did a little modifications (just renamed a couple of variables and added a menu) and when I tried to run it I faced a problem when trying to rotate the tree. Insertion works fine until the tree get's unbalanced specially when the uncle becomes "Black" my program fails to rotate the tree and it just crashes. So Let me explain you the flow of the program: whenever we insert a new node a function named insert
gets called, after a successful insertion it calls another function named insertfixup
which checks whether any properties of the Red Black Tree have been violated and if so then it rotates the tree on the basis of whether the uncle of the problematic node is RED or BLACK if the uncle is Red then it works fine, but soon as the uncle becomes Black then it just crashes. Can someone please examine the code I have given below and point out what exactly is causing the problem, I doubt it has something to do with the pointers but can't figure out what is actually happening,
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct RB_Tree {
struct RB_Tree *left, *right, *parent;
int info;
char color;
} node;
int count = 0;
void left_rotate(node **root, node *par) {
node *child = par->right;
par->right = child->left;
if (child->left!=NULL)
child->left->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par == par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->left = par;
par->parent = child;
}
void right_rotate(node **root, node *par) {
node *child = par->left;
par->left = child->right;
if (child->right!=NULL)
child->right->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par = par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->right = par;
par->parent = child;
}
void insertFixup(node **root, node *new) {
while (new != *root && new->parent->color == 'R') {
node *uncle;
//Find uncle and store uncle in "uncle" variable!
if (new->parent == new->parent->parent->left) {
uncle = new->parent->parent->right;
} else {
uncle = new->parent->parent->left;
}
if (uncle == NULL || uncle->color == 'B') {
if (new->parent == new->parent->parent->left && new == new->parent->left) {
printf("Inside ll case before rot");
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->right) {
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
left_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->left && new == new->parent->right) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
//printf("\nHere we are in the left right!");
left_rotate(root, new->parent);
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->left) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent);
left_rotate(root, new->parent->parent);
}
}
if (uncle) {
if (uncle->color == 'R') {
uncle->color = 'B';
new->parent->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
}
}
(*root)->color = 'B';
}
void insert(node **root, int data) {
node *new = (node*)malloc(sizeof(node));
new->info = data;
new->parent = new->left = new->right = NULL;
if (*root == NULL) {
(*root) = new;
new->color = 'B';
} else {
node *par;
node *temp = (*root);
while (temp) {
par = temp;
if(new->info > temp->info)
temp = temp->right;
else
temp = temp->left;
}
new->parent = par;
if (par->info > new->info)
par->left = new;
else
par->right = new;
new->color = 'R';
insertFixup(root, new);
}
}
void main() {
int men, c, data;
node *root = NULL;
while (1) {
system("cls");
printf("1.) Insert\n");
printf("2.) exit\n");
printf("Enter your choice : ");
scanf("%d", &men);
switch (men) {
case 1:
printf("Enter data : ");
scanf("%d", &data);
insert(&root, data);
printf("%d successfully added!", data);
break;
case 2:
exit(0);
default:
printf("Invalid choice!");
while ((c = fgetc(stdin)) != '\n') {}
break;
}
getch();
}
}
conio.h
is windows specific (not portable) Suggest rewriting such thatconio.h
and related functions are replaced with c library functions – user3629249void main() {
Although visual studio (and some other related compilers) allow avoid
return type, there are only two valid signatures formain()
. They are:int main( void )
andint main( int argc, char* argv[] )
– user3629249printf("1.) Insert\n"); printf("2.) exit\n"); printf("Enter your choice : ");
The functionprintf()
is very expensive in CPU cycles. Suggest:printf("%s", "1.) Insert\n" "2.) exit\n" "Enter your choice : ");
– user3629249system()
cls
is not portable Suggest "\f" (formfeed) or the ANSI escape sequence:printf( "\1b[2J\n" );
– user3629249int count = 0;
The global variable:count
is not used anywhere in the posted code. So could (and probably should) be eliminated – user3629249