From: a bellenir Date: Wed, 6 Aug 2014 01:06:23 +0000 (+0000) Subject: fix tree root when rotating nodes X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=fe575e704e04b3626ce71adc8b41ccbbc73441bd;p=projs%2Flibcds.git fix tree root when rotating nodes --- diff --git a/source/rb/rb.c b/source/rb/rb.c index 69d24a7..ab7ac00 100644 --- a/source/rb/rb.c +++ b/source/rb/rb.c @@ -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); } } } diff --git a/tests/test_rb.c b/tests/test_rb.c index f559fd1..2f2fe2c 100644 --- a/tests/test_rb.c +++ b/tests/test_rb.c @@ -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); + } }