]> git.mdlowis.com Git - projs/libcds.git/commitdiff
fix tree root when rotating nodes
authora bellenir <a@bellenir.com>
Wed, 6 Aug 2014 01:06:23 +0000 (01:06 +0000)
committera bellenir <a@bellenir.com>
Wed, 6 Aug 2014 01:06:23 +0000 (01:06 +0000)
source/rb/rb.c
tests/test_rb.c

index 69d24a7061cc7b53ae4a63a5e884cc9f04def1aa..ab7ac002adb2977cd0591a679b4d826aec6f76d0 100644 (file)
@@ -38,7 +38,7 @@ static rb_color_t node_color(rb_node_t* node){
        return (node ? node->color : BLACK);
 }
 
-static void rb_tree_rotate_outside_left(rb_node_t* node){
+static void rb_tree_rotate_outside_left(rb_tree_t* tree, rb_node_t* node){
        rb_node_t* parent = node->parent;
        rb_node_t* grandparent = (parent ? parent->parent : NULL);
        //rb_node_t* uncle = (grandparent ? (parent == grandparent->left ? grandparent->right : grandparent->left) : NULL);
@@ -53,13 +53,15 @@ static void rb_tree_rotate_outside_left(rb_node_t* node){
        grandparent->left = parent->right; //safe to overwrite gp->left. it is parent.
        parent->right = grandparent;
        grandparent->parent = parent;
+       //repair the tree root
+       if(tree->root == grandparent) tree->root = parent;
        //repaint nodes as needed:
        parent->color = BLACK;
        grandparent->color = RED;
 }
 
 //mirror of above:
-static void rb_tree_rotate_outside_right(rb_node_t* node){
+static void rb_tree_rotate_outside_right(rb_tree_t* tree, rb_node_t* node){
        rb_node_t* parent = node->parent;
        rb_node_t* grandparent = (parent ? parent->parent : NULL);
        //rb_node_t* uncle = (grandparent ? (parent == grandparent->left ? grandparent->right : grandparent->left) : NULL);
@@ -72,13 +74,15 @@ static void rb_tree_rotate_outside_right(rb_node_t* node){
        grandparent->right = parent->left; //safe to overwrite gp->right. it is parent.
        parent->left = grandparent;
        grandparent->parent = parent;
+       //repair the tree root
+       if(tree->root == grandparent) tree->root = parent;
        //repaint nodes
        parent->color = BLACK;
        grandparent->color = RED;
 }
 
 //NODE:the node to be inserted
-static void rb_tree_recolor(rb_node_t* node){
+static void rb_tree_recolor(rb_tree_t* tree, rb_node_t* node){
        rb_node_t* parent = node->parent;
        rb_node_t* grandparent = (parent ? parent->parent : NULL);
        rb_node_t* uncle = (grandparent ? (parent == grandparent->left ? grandparent->right : grandparent->left) : NULL);
@@ -91,7 +95,7 @@ static void rb_tree_recolor(rb_node_t* node){
                grandparent->color = RED;
                parent->color = BLACK;
                uncle->color = BLACK;
-               rb_tree_recolor(grandparent);
+               rb_tree_recolor(tree, grandparent);
        }else if(node == parent->right && parent == grandparent->left){
                //parent is red, uncle is black, "inside left" case
                //first rotate node and parent
@@ -101,7 +105,7 @@ static void rb_tree_recolor(rb_node_t* node){
                parent->parent = node;
                parent->right = NULL;
                //tree now transformed to an "outside left" case
-               rb_tree_rotate_outside_left(parent);
+               rb_tree_rotate_outside_left(tree, parent);
        }else if(node == parent->left && parent == grandparent->right){
                //parent is red, uncle is black, "inside right" case
                //first rotate node and parent
@@ -111,27 +115,27 @@ static void rb_tree_recolor(rb_node_t* node){
                parent->parent = node;
                parent->left = NULL;
                //tree now transformed to an "outside right" case
-               rb_tree_rotate_outside_right(parent);
+               rb_tree_rotate_outside_right(tree, parent);
        }else if(node == parent->left && parent == grandparent->left){
                //parent is red, uncle is black, "outside left" case
-               rb_tree_rotate_outside_left(node);
+               rb_tree_rotate_outside_left(tree, node);
        }else if(node == parent->right && parent == grandparent->right){
                //parent is red, uncle is black, "outside right" case
-               rb_tree_rotate_outside_right(node);
+               rb_tree_rotate_outside_right(tree, node);
        }
 }
 
 static void rb_tree_insert_node(rb_tree_t* tree, rb_node_t* node, rb_node_t* parent){
        if(NULL == parent){ /* inserting root of the tree */
                tree->root = node;
-               rb_tree_recolor(node);
+               rb_tree_recolor(tree, node);
        }else if(node->contents < parent->contents){
                if(parent->left){
                        rb_tree_insert_node(tree, node, parent->left);
                }else{
                        node->parent = parent;
                        parent->left = node;
-                       rb_tree_recolor(node);
+                       rb_tree_recolor(tree, node);
                }
        }else{
                if(parent->right){
@@ -139,7 +143,7 @@ static void rb_tree_insert_node(rb_tree_t* tree, rb_node_t* node, rb_node_t* par
                }else{
                        node->parent = parent;
                        parent->right = node;
-                       rb_tree_recolor(node);
+                       rb_tree_recolor(tree, node);
                }
        }
 }
index f559fd193e15e229e5e9f63600c0f61fd81282b6..2f2fe2c59c83164ba47d0d13d7137f4a035292f8 100644 (file)
@@ -117,5 +117,33 @@ TEST_SUITE(RB) {
                CHECK(rb_tree_is_valid(tree));
                mem_release(tree);
     }
+    TEST(Verify_rb_insert_parent_uncle_mismatch_outside_left){
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 42);
+               rb_node_t* node2 = rb_tree_insert(tree, 32);
+               CHECK(RED == node2->color);
+               //tree->root->right == NULL ; black implicitly
+               rb_node_t* node3 = rb_tree_insert(tree, 15);
+               CHECK(node2 == tree->root);
+               //check node2 fields 
+               CHECK(node3 == node2->left);
+               CHECK(node1 == node2->right);
+               CHECK(NULL == node2->parent)
+               CHECK(BLACK == node2->color);
+               CHECK(32 == node2->contents);
+               //check node1 fields
+               CHECK(NULL == node1->left);
+               CHECK(NULL == node1->right);
+               CHECK(node2 == node1->parent)
+               CHECK(RED == node1->color);
+               CHECK(42 == node1->contents);
+               //check node3 fields
+               CHECK(NULL == node3->left);
+               CHECK(NULL == node3->right);
+               CHECK(node2 == node3->parent);
+               CHECK(RED == node3->color);
+               CHECK(15 == node3->contents);
+               mem_release(tree);
+    }
 }