TheAlgorithms-C/data_structures/binary_trees/redBlackTree.c

679 lines
19 KiB
C
Raw Normal View History

2019-10-01 16:59:14 +03:00
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct node{
int val;
struct node* par;
struct node* left;
struct node* right;
int color;
}Node;
// Create a new node
Node* newNode(int val, Node* par){
Node* create = (Node*)(malloc(sizeof(Node)));
create->val = val;
create->par = par;
create->left = NULL;
create->right = NULL;
create->color = 1;
}
// Check if the node is the leaf
int isLeaf(Node* n){
if(n->left == NULL && n->right == NULL){
return 1;
}
return 0;
}
// Left Rotate
Node* leftRotate(Node* node){
Node* parent = node->par;
Node* grandParent = parent->par;
parent->right = node->left;
if(node->left != NULL){
node->left->par = parent;
}
node->par = grandParent;
parent->par = node;
node->left = parent;
if(grandParent != NULL){
if(grandParent->right == parent){
grandParent->right = node;
}
else{
grandParent->left = node;
}
}
return node;
}
// Right Rotate
Node* rightRotate(Node* node){
Node* parent = node->par;
Node* grandParent = parent->par;
parent->left = node->right;
if(node->right != NULL){
node->right->par = parent;
}
node->par = grandParent;
parent->par = node;
node->right = parent;
if(grandParent != NULL){
if(grandParent->right == parent){
grandParent->right = node;
}
else{
grandParent->left = node;
}
}
return node;
}
// Check the node after the insertion step
void checkNode(Node* node){
// If the node is the root
if(node == NULL || node->par == NULL){
return;
}
Node* child = node;
//If it is a black node or its parent is a black node
if(node->color == 0 || (node->par)->color == 0){
// Dont Do Anything
return;
}
// Both parent and child are red
// Check For Uncle
Node* parent = node->par;
Node* grandParent = parent->par;
// If grandParent is NULL, then parent is the root.
// Just make the root black.
if(grandParent == NULL){
parent->color = 0;
return;
}
// If both the children of the grandParent are red
if(grandParent->right != NULL && (grandParent->right)->color == 1 && grandParent->left != NULL && (grandParent->left)->color == 1){
// Make the grandParent red and both of its children black
(grandParent->right)->color = 0;
(grandParent->left)->color = 0;
grandParent->color = 1;
return;
}
else{
// The only option left is rotation.
Node* greatGrandParent = grandParent->par;
// Right Case
if(grandParent->right == parent){
//Right Right Case
if(parent->right == node){
grandParent->right = parent->left;
if(parent->left != NULL){
(parent->left)->par = grandParent;
}
parent->left = grandParent;
grandParent->par = parent;
// Attach to existing Tree;
parent->par = greatGrandParent;
if(greatGrandParent != NULL){
if(greatGrandParent->left != NULL && greatGrandParent->left == grandParent){
greatGrandParent->left = parent;
}
else{
greatGrandParent->right = parent;
}
}
// Change the colors
parent->color = 0;
grandParent->color = 1;
}
else{ // Right Left Case
// First step -> Parent Child Rotation
parent->left = child->right;
if(child->right != NULL){
(child->right)->par = parent;
}
child->right = parent;
parent->par = child;
// Second step -> Child and GrandParent Rotation
grandParent->right = child->left;
if(child->left != NULL){
(child->left)->par = grandParent;
}
child->left = grandParent;
grandParent->par = child;
// Attach to the existing tree
child->par = greatGrandParent;
if(greatGrandParent != NULL){
if(greatGrandParent->left != NULL && greatGrandParent->left == grandParent){
greatGrandParent->left = child;
}
else{
greatGrandParent->right = child;
}
}
// Change The Colors
child->color = 0;
grandParent->color = 1;
}
}
else{ // Left Case
//Left Left Case
if(parent->left == node){
grandParent->left = parent->right;
if(parent->right != NULL){
(parent->right)->par = grandParent;
}
parent->right = grandParent;
grandParent->par = parent;
// Attach to existing Tree;
parent->par = greatGrandParent;
if(greatGrandParent != NULL){
if(greatGrandParent->left != NULL && greatGrandParent->left == grandParent){
greatGrandParent->left = parent;
}
else{
greatGrandParent->right = parent;
}
}
// Change the colors
parent->color = 0;
grandParent->color = 1;
}
else{ //Left Right Case
// First step -> Parent Child Rotation
parent->right = child->left;
if(child->left != NULL){
(child->left)->par = parent;
}
child->left = parent;
parent->par = child;
// Second step -> Child and GrandParent Rotation
grandParent->left = child->right;
if(child->right != NULL){
(child->right)->par = grandParent;
}
child->right = grandParent;
grandParent->par = child;
// Attach to the existing tree
child->par = greatGrandParent;
if(greatGrandParent != NULL){
if(greatGrandParent->left != NULL && greatGrandParent->left == grandParent){
greatGrandParent->left = child;
}
else{
greatGrandParent->right = child;
}
}
// Change The Colors
child->color = 0;
grandParent->color = 1;
}
}
}
}
// To insert a node in the existing tree
void insertNode(int val, Node** root){
Node* buffRoot = *root;
while(buffRoot){
if(buffRoot->val > val){
// Go left
if(buffRoot->left != NULL){
buffRoot = buffRoot->left;
}
else{
//Insert The Node
Node* toInsert = newNode(val, buffRoot);
buffRoot->left = toInsert;
buffRoot = toInsert;
//Check For Double Red Problems
break;
}
}
else{
// Go right
if(buffRoot->right != NULL){
buffRoot = buffRoot->right;
}
else{
//Insert The Node
Node* toInsert = newNode(val, buffRoot);
buffRoot->right = toInsert;
buffRoot = toInsert;
//Check For Double Red Problems
break;
}
}
}
while(buffRoot != *root){
checkNode(buffRoot);
if(buffRoot->par == NULL){
*root = buffRoot;
break;
}
buffRoot = buffRoot->par;
if(buffRoot == *root){
buffRoot->color = 0;
}
}
}
void checkForCase2(Node* toDelete, int delete, int fromDirection, Node** root){
if(toDelete == (*root)){
(*root)->color = 0;
return;
}
if(!delete && toDelete->color == 1){
if(!fromDirection){
if(toDelete->right != NULL){
toDelete->right->color = 1;
}
}
else{
if(toDelete->left != NULL){
toDelete->left->color = 1;
}
}
toDelete->color = 0;
return;
}
// Get the sibling for further inspection
Node* sibling;
Node* parent = toDelete->par;
int locateChild = 0; // 0 if toDeleted is left of its parent else 1
if(parent->right == toDelete){
sibling = parent->left;
locateChild = 1;
}
else{
sibling = parent->right;
}
//Case 2.1. i.e. if the any children of the sibling is red
if((sibling->right != NULL && sibling->right->color == 1) || (sibling->left != NULL && sibling->left->color == 1)){
if(sibling->right != NULL && sibling->right->color == 1){
// Sibling is left and child is right. i.e. LEFT RIGHT ROTATION
if(locateChild == 1){
int parColor = parent->color;
// Step 1: Left rotate sibling
sibling = leftRotate(sibling->right);
// Step 2: Right rotate updated sibling
parent = rightRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
// Step 3: Update the colors
parent->color = parColor;
parent->left->color = 0;
parent->right->color = 0;
// Delete the node (present at parent->right->right)
if(delete){
if(toDelete->left != NULL){
toDelete->left->par = parent->right;
}
parent->right->right = toDelete->left;
free(toDelete);
}
}
else{ // Sibling is right and child is also right. i.e. LEFT LEFT ROTATION
int parColor = parent->color;
// Left Rotate the sibling
parent = leftRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
// Update Colors
parent->color = parColor;
parent->left->color = 0;
parent->right->color = 0;
// Delete the node (present at parent->left->left)
if(delete){
if(toDelete->right != NULL){
toDelete->right->par = parent->left;
}
parent->left->left = toDelete->left;
free(toDelete);
}
}
}
else{
// Sibling is right and child is left. i.e. RIGHT LEFT ROTATION
if(locateChild == 0){
int parColor = parent->color;
// Step 1: Right rotate sibling
sibling = rightRotate(sibling->left);
// printf("%d - reached\n", sibling->val);
// return;
// Step 2: Left rotate updated sibling
parent = leftRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
// Step 3: Update the colors
parent->color = parColor;
parent->left->color = 0;
parent->right->color = 0;
// Delete the node (present at parent->left->left)
if(delete){
if(toDelete->right != NULL){
toDelete->right->par = parent->left;
}
parent->left->left = toDelete->right;
free(toDelete);
}
}
else{ // Sibling is left and child is also left. i.e. RIGHT RIGHT ROTATION
int parColor = parent->color;
// Right Rotate the sibling
parent = rightRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
// Update Colors
parent->color = parColor;
parent->left->color = 0;
parent->right->color = 0;
// Delete the node (present at parent->right->right)
if(delete){
if(toDelete->left != NULL){
toDelete->left->par = parent->right;
}
parent->right->right = toDelete->left;
free(toDelete);
}
}
}
}
else if(sibling->color == 0){ //Make the sibling red and recur for its parent
// Recolor the sibling
sibling->color = 1;
// Delete if necessary
if(delete){
if(locateChild){
toDelete->par->right = toDelete->left;
if(toDelete->left != NULL){
toDelete->left->par = toDelete->par;
}
}
else{
toDelete->par->left = toDelete->right;
if(toDelete->right != NULL){
toDelete->right->par = toDelete->par;
}
}
}
checkForCase2(parent, 0, locateChild, root);
}
else{ // Bring the sibling on top and apply 2.1 or 2.2 accordingly
if(locateChild){ //Right Rotate
toDelete->par->right = toDelete->left;
if(toDelete->left != NULL){
toDelete->left->par = toDelete->par;
}
parent = rightRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
parent->color = 0;
parent->right->color = 1;
checkForCase2(parent->right, 0, 1, root);
}
else{ // Left Rotate
toDelete->par->left = toDelete->right;
if(toDelete->right != NULL){
toDelete->right->par = toDelete->par;
}
parent = leftRotate(sibling);
// Check if the root is rotated
if(parent->par == NULL){
*root = parent;
}
printf("\nroot - %d - %d\n", parent->val, parent->left->val);
parent->color = 0;
parent->left->color = 1;
checkForCase2(parent->left, 0, 0, root);
}
}
}
// To delete a node from the tree
void deleteNode(int val, Node** root){
Node* buffRoot = *root;
//Search for the element in the tree
while(1){
if(val == buffRoot->val){
// Node Found
break;
}
if(val > buffRoot->val){
if(buffRoot->right != NULL){
buffRoot = buffRoot->right;
}
else{
printf("Node Not Found!!!");
return;
}
}
else{
if(buffRoot->left != NULL){
buffRoot = buffRoot->left;
}
else{
printf("Node Not Found!!!");
return;
}
}
}
Node* toDelete = buffRoot;
// Look for the leftmost of right node or right most of left node
if(toDelete->left != NULL){
toDelete = toDelete->left;
while(toDelete->right != NULL){
toDelete = toDelete->right;
}
}
else if(toDelete->right != NULL){
toDelete = toDelete->right;
while(toDelete->left != NULL){
toDelete = toDelete->left;
}
}
if(toDelete == *root){
*root = NULL;
return;
}
// Swap the values
buffRoot->val = toDelete->val;
toDelete->val = val;
// Checking for case 1
if(toDelete->color == 1 || (toDelete->left != NULL && toDelete->left->color == 1) || (toDelete->right != NULL && toDelete->right->color == 1)){
// if it is a leaf
if(toDelete->left == NULL && toDelete->right == NULL){
// Delete instantly
if(toDelete->par->left == toDelete){
toDelete->par->left = NULL;
}
else{
toDelete->par->right = NULL;
}
}
else{ // else its child should be red
// Check for the exitstence of left node
if(toDelete->left != NULL){
// The node should be right to its parent
toDelete->par->right = toDelete->left;
toDelete->left->par = toDelete->par;
toDelete->left->color = 1;
}
else{ // else the right node should be red
toDelete->par->left = toDelete->right;
toDelete->right->par = toDelete->par;
toDelete->right->color = 1;
}
}
// Remove the node from memory
free(toDelete);
}
else{ // Case 2
checkForCase2(toDelete, 1, ((toDelete->par->right == toDelete)), root);
}
}
void printInorder(Node* root){
if(root != NULL){
printInorder(root->left);
printf("%d c-%d ", root->val, root->color);
printInorder(root->right);
}
}
void checkBlack(Node* temp,int c){
if (temp==NULL){
printf("%d ",c);
return ;
}
if (temp->color==0){
c++;
}
checkBlack(temp->left,c);
checkBlack(temp->right,c);
}
int main(){
Node* root = NULL;
int scanValue, choice = 1;
printf("1 - Input\n2 - Delete\n3 - Inorder Traversel\n0 - Quit\n\nPlease Enter the Choice - ");
scanf("%d", &choice);
while(choice){
switch(choice){
case 1:
printf("\n\nPlease Enter A Value to insert - ");
scanf("%d", &scanValue);
if(root == NULL){
root = newNode(scanValue, NULL);
root->color = 0;
}
else{
insertNode(scanValue, &root);
}
printf("\nSuccessfully Inserted %d in the tree\n\n", scanValue);
break;
case 2:
printf("\n\nPlease Enter A Value to Delete - ");
scanf("%d", &scanValue);
deleteNode(scanValue, &root);
printf("\nSuccessfully Inserted %d in the tree\n\n", scanValue);
break;
case 3:
printf("\nInorder Traversel - ");
printInorder(root);
printf("\n\n");
// checkBlack(root,0);
// printf("\n");
break;
default:
if(root != NULL){
printf("Root - %d\n", root->val);
}
}
printf("1 - Input\n2 - Delete\n3 - Inorder Traversel\n0 - Quit\n\nPlease Enter the Choice - ");
scanf("%d", &choice);
}
}
// 32 12 50 53 1 2 3 4 5 6 7 8 9