]> git.mdlowis.com Git - projs/libcds.git/commitdiff
more rm cases
authora bellenir <a@bellenir.com>
Tue, 12 Aug 2014 09:49:56 +0000 (09:49 +0000)
committera bellenir <a@bellenir.com>
Tue, 12 Aug 2014 09:49:56 +0000 (09:49 +0000)
source/rb/rb.c
tests/test_rb.c

index 639c2b3f2cd04350d1a2b8594571e453c91b07d0..674c0a2f6cd97be417b58f68c05a57cf1db5a8da 100644 (file)
@@ -232,10 +232,49 @@ static void rb_tree_delete_node(rb_tree_t* tree, rb_node_t* node){
                                rotate_left(tree, parent);
                        }
                        mem_release(node);
+               } else if(node == parent->right){
+                       //node is black. parent is black. node is parent's right child.
+                       rb_node_t* sib = parent->left;
+                       //remove/release the node
+                       parent->right = NULL;
+                       node->parent = NULL;
+                       mem_release(node);
+                       //rebalance the tree
+                       //fix sibbling if red first
+                       if(RED == node_color(sib)){
+                               sib->color = BLACK;
+                               sib->right->color = RED;
+                               //sib->left->color = RED; //unnecessary; gets overwritten anyway.
+                       }
+                       //rotate "inside" case to "outside"
+                       if(sib->right && !sib->left){
+                               sib->right->color = BLACK;
+                               rotate_left(tree, sib);
+                       }
+                       if(sib->left) sib->left->color = BLACK;
+                       rotate_right(tree, parent);
                } else {
-                       //node is not root.
-                       //parent is black
-                       //node is black, and has only leaf children or tree is invalid.
+                       //node is black. parent is black. node is parent's left child.
+                       rb_node_t* sib = parent->right;
+                       //remove/release the node
+                       parent->left = NULL;
+                       node->parent = NULL;
+                       mem_release(node);
+                       //rebalance the tree
+                       //fix sibbling if red first
+                       if(RED == node_color(sib)){
+                               sib->color = BLACK;
+                               sib->left->color = RED;
+                               //sib->right->color = RED; //unnecessary; gets overwritten anyway.
+                       }
+                       //rotate "inside" case to "outside"
+                       if(sib->left && !sib->right){
+                               sib->left->color = BLACK;
+                               rotate_right(tree, sib);
+                       }
+                       if(sib->right) sib->right->color = BLACK;
+                       rotate_left(tree, parent);
+
                }
        }
 }
index e0885ae626f209d63b60be02bca3b68b4c58b141..8b8ee8ad71c5b805fb21cc2ac65c8acb49c7afa0 100644 (file)
@@ -1038,11 +1038,296 @@ TEST_SUITE(RB) {
        //properties of RBT imply node has a sibbling
        //five subcases
        //4.1: sibbling is black, no children //TODO
-       //4.2: sibbling is black, left red child
-       //4.3: sibbling is black, right red child
+       //4.2: sibbling is black, outside red child
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_outside_red_child_right){
+               int target = 99;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 88); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 42); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 22); //sib child
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->right);
+               CHECK(node3 == node1->left);
+               CHECK(node4 == node3->left);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_outside_red_child_left){
+               int target = 8;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 42); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 88); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 123); //sib child
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->left);
+               CHECK(node3 == node1->right);
+               CHECK(node4 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
+       //4.3: sibbling is black, inside red child
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_inside_red_child_right){
+               int target = 99;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 88); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 42); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 55); //sib child
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->right);
+               CHECK(node3 == node1->left);
+               CHECK(node4 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_inside_red_child_left){
+               int target = 8;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 42); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 88); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 70); //sib child
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->left);
+               CHECK(node3 == node1->right);
+               CHECK(node4 == node3->left);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
        //4.4: sibbling is black, two red children
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_two_children_right){
+               int target = 99;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 88); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 42); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 22); //sib child 1
+               rb_node_t* node5 = rb_tree_insert(tree, 55); //sib child 2
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               node5->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->right);
+               CHECK(node3 == node1->left);
+               CHECK(node4 == node3->left);
+               CHECK(node5 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
+       TEST(Verify_rb_delete_black_node_from_black_parent_sib_has_two_children_left){
+               int target = 8;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 42); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 88); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 70); //sib child 1
+               rb_node_t* node5 = rb_tree_insert(tree, 123); //sib child 2
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = BLACK;
+               node4->color = RED;
+               node5->color = RED;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->left);
+               CHECK(node3 == node1->right);
+               CHECK(node4 == node3->left);
+               CHECK(node5 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
        //4.5: sibbling is red, two black children
+       TEST(Verify_rb_delete_black_node_from_black_parent_red_sib_right){
+               int target = 99;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 88); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 42); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 22); //sib child 1
+               rb_node_t* node5 = rb_tree_insert(tree, 55); //sib child 2
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = RED;
+               node4->color = BLACK;
+               node5->color = BLACK;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->right);
+               CHECK(node3 == node1->left);
+               CHECK(node4 == node3->left);
+               CHECK(node5 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
+       TEST(Verify_rb_delete_black_node_from_black_parent_red_sib_left){
+               int target = 8;
+               //create tree w/ several nodes
+               rb_tree_t* tree = rb_tree_new();
+               rb_node_t* node1 = rb_tree_insert(tree, 42); //root
+               rb_node_t* node2 = rb_tree_insert(tree, target); //target
+               rb_node_t* node3 = rb_tree_insert(tree, 88); //sibbling
+               rb_node_t* node4 = rb_tree_insert(tree, 70); //sib child 1
+               rb_node_t* node5 = rb_tree_insert(tree, 123); //sib child 2
+               //force colors to match scenario being tested
+               (void)node1;
+               node2->color = BLACK;
+               node3->color = RED;
+               node4->color = BLACK;
+               node5->color = BLACK;
+               //confirm tree is valid & node can be found
+               CHECK(OK == rb_tree_is_valid(tree));
+               CHECK(node2 == rb_tree_lookup(tree, target));
+               //confirm tree is shaped as expected
+               CHECK(node1 == tree->root);
+               CHECK(node2 == node1->left);
+               CHECK(node3 == node1->right);
+               CHECK(node4 == node3->left);
+               CHECK(node5 == node3->right);
+               //delete the node from the tree
+               mem_retain(node2);
+               rb_tree_delete(tree, target);
+               //confirm refcounting decremented, node no longer in tree, node pointers nulld and tree still valid
+               CHECK(1 == mem_num_references(node2));
+               CHECK(NULL == rb_tree_lookup(tree, target));
+               CHECK(NULL == node2->parent);
+               CHECK(NULL == node2->left);
+               CHECK(NULL == node2->right);
+               CHECK(OK == rb_tree_is_valid(tree));
+               mem_release(node2);
+               mem_release(tree);
+       }
        //second class: deleting nodes that have two children
+       //TODO
        //third class: special cases: deleting root
        TEST(Verify_rb_delete_root_node_with_single_red_left_child){
                rb_tree_t* tree = rb_tree_new();