From: a bellenir Date: Tue, 12 Aug 2014 09:49:56 +0000 (+0000) Subject: more rm cases X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3b506ebc252389ca5fcc04b8f39af1167e8dbf4d;p=projs%2Flibcds.git more rm cases --- diff --git a/source/rb/rb.c b/source/rb/rb.c index 639c2b3..674c0a2 100644 --- a/source/rb/rb.c +++ b/source/rb/rb.c @@ -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); + } } } diff --git a/tests/test_rb.c b/tests/test_rb.c index e0885ae..8b8ee8a 100644 --- a/tests/test_rb.c +++ b/tests/test_rb.c @@ -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();