diff --git a/include/tree.h b/include/tree.h index abb2883..3a84075 100644 --- a/include/tree.h +++ b/include/tree.h @@ -14,8 +14,8 @@ #include "common.h" typedef enum { - RED = 0x01, - BLACK = 0x02, + RBT_RED = 0x00, + RBT_BLACK = 0x01, }rbt_color; struct _tree_node diff --git a/src/tree.c b/src/tree.c index 8d905d0..8ecf894 100644 --- a/src/tree.c +++ b/src/tree.c @@ -102,7 +102,7 @@ static struct _tree_node* tree_turn_right(struct _tree* self, struct _tree_node* return node; } -static struct _tree_node* tree_trun_left_then_right(struct _tree* self, struct _tree_node* root) +static struct _tree_node* tree_turn_left_then_right(struct _tree* self, struct _tree_node* root) { assert(self != NULL); assert(root != NULL); @@ -115,7 +115,7 @@ static struct _tree_node* tree_trun_left_then_right(struct _tree* self, struct _ return node; } -static struct _tree_node* tree_trun_right_then_left(struct _tree* self, struct _tree_node* root) +static struct _tree_node* tree_turn_right_then_left(struct _tree* self, struct _tree_node* root) { assert(self != NULL); assert(root != NULL); @@ -222,7 +222,7 @@ static bool tree_avl_rebalance(struct _tree* self, struct _tree_node* root) } else { - root = tree_trun_right_then_left(self, root); + root = tree_turn_right_then_left(self, root); } } else if(balance == -2) @@ -233,7 +233,7 @@ static bool tree_avl_rebalance(struct _tree* self, struct _tree_node* root) } else { - root = tree_trun_left_then_right(self, root); + root = tree_turn_left_then_right(self, root); } } @@ -257,7 +257,7 @@ static bool tree_avl_rebalance(struct _tree* self, struct _tree_node* root) return false; } int balance = 0; - + do { tree_set_balance(self, root); @@ -270,7 +270,7 @@ static bool tree_avl_rebalance(struct _tree* self, struct _tree_node* root) } else { - root = tree_trun_right_then_left(self, root); + root = tree_turn_right_then_left(self, root); } } else if(balance == -2) @@ -281,7 +281,7 @@ static bool tree_avl_rebalance(struct _tree* self, struct _tree_node* root) } else { - root = tree_trun_left_then_right(self, root); + root = tree_turn_left_then_right(self, root); } } @@ -1061,6 +1061,106 @@ bool tree_set_color(struct _tree_node* node, rbt_color color) return true; } +/** + * @brief + * + * 以 balance = rigth - left 为标准,调整平衡因子 + * + * | 情况 | root->balance | node->balance | 调整方式 | + * | ---- | ------------ | -------------- | -------- | + * | 1 | 2 | >= 0 | 左旋 + * | 2 | 2 | < 0 | 先右旋后左旋 + * | 3 | -2 | <= 0 | 右旋 + * | 4 | -2 | > 0 | 先左旋后右旋 + * + * @param self + * @return true + * @return false + */ +static bool tree_rb_rebalance(struct _tree* self, struct _tree_node* node) +{ + assert(self != NULL); + if(node == NULL) + { + return false; + } + struct _tree_node* father = NULL; + struct _tree_node* grandfather = NULL; + struct _tree_node* uncle = NULL; + + /** + * @brief 考虑三种情况,其余三种对称即可 + * + * 新插入节点为红色,若父节点为黑色,则不用处理 + * + * | 情况 | 说明 | 调整方式 | + * | ---- | --- | -------- | + * | 1 | + */ + while(node->parent != NULL && node->parent->color == RBT_RED) + { + father = node->parent; + grandfather = father->parent; + if(father == grandfather->left) + { + uncle = grandfather->right; + if(uncle != NULL && uncle->color == RBT_RED) // uncle is red + { + father->color = RBT_BLACK; + uncle->color = RBT_BLACK; + grandfather->color = RBT_RED; + node = grandfather; + } + else // uncle is black + { + if(node == father->right) + { + node = tree_turn_left(self, father); + node->color = RBT_BLACK; + } + else + { + father->color = RBT_BLACK; + } + grandfather->color = RBT_RED; + tree_turn_right(self, grandfather); + } + } + else + { + uncle = grandfather->left; + if(uncle != NULL && uncle->color == RBT_RED) // uncle is red + { + father->color = RBT_BLACK; + uncle->color = RBT_BLACK; + grandfather->color = RBT_RED; + node = grandfather; + } + else // uncle is black + { + if(node == father->left) + { + node = tree_turn_right(self, father); + node->color = RBT_BLACK; + } + else + { + father->color = RBT_BLACK; + } + grandfather->color = RBT_RED; + tree_turn_left(self, grandfather); + } + } + } + + if(node->parent == NULL) + { + self->_root = node; + node->color = RBT_BLACK; + } + return true; +} + bool tree_rb_init(struct _tree *self, uint32_t obj_size) { assert(self != NULL); @@ -1084,7 +1184,7 @@ bool tree_rb_init(struct _tree *self, uint32_t obj_size) self->order = tree_order; self->find = tree_avl_find; self->height = tree_height; - self->rebalance = tree_avl_rebalance; + self->rebalance = tree_rb_rebalance; self->find_max = tree_find_max; self->find_min = tree_find_min; self->max = tree_max; diff --git a/test/test_tree.c b/test/test_tree.c index 5c155c0..ced3a5a 100644 --- a/test/test_tree.c +++ b/test/test_tree.c @@ -1,272 +1,6 @@ #include "test.h" -#ifdef TREE_TEST - -static void tree_data_display(tree_data_t data) -{ - printf("%d ", data); -} - -#ifdef TREE_RECURSION - -#define TREE_DISP_DEPTH_PRE(tree) {tree_traversal_depth_preorder(tree,tree_data_display);printf("\n");} -#define TREE_DISP_DEPTH_IN(tree) {tree_traversal_depth_inorder(tree,tree_data_display);printf("\n");} - -// tree display -#define TREE_DISP(tree) TREE_DISP_DEPTH_IN(tree) - -void tree_test(void) -{ - int32_t i = 0; - // tree_data_t dat[10] = {5,0,2,4,3,1,8,7,9,6}; // debug data - tree_data_t dat[10] = { 0,1,2,3,4,5,6,7,8,9 }; // test data1 - // tree_data_t dat[10] = { 3,1,2,5,4,8,6,7,9,0 }; // test data2 - tree_data_t tmp; - ptree_node_t tree = NULL; - - tree_init(&tree); - - for (i = 0; i < 10; i++) - { - tree_insert(tree, dat[i]); - } - printf("tree : "); - TREE_DISP(tree); - - tree_get_min(tree, &tmp); - if (tmp == 0) - { - printf("success -> tree_get_min is %d\n", tmp); - } - else - { - printf("failure -> tree_get_min is %d ?\n", tmp); - } - - tree_get_max(tree, &tmp); - if (tmp == 9) - { - printf("success -> tree_get_max is %d\n", tmp); - } - else - { - printf("failure -> tree_get_max is %d ?\n", tmp); - } - - // delete the root - tree_delete(tree, 5); - printf("del %d: ", 5); - TREE_DISP(tree); - - // delete the leaf - tree_delete(tree, 3); - printf("del %d: ", 3); - TREE_DISP(tree); - - // delete the node which has two nodes - tree_delete(tree, 8); - printf("del %d: ", 8); - TREE_DISP(tree); - - tree_clear(tree); - printf("success -> tree_clear success!\n"); - if (tree_empty(tree)) - { - printf("success -> the tree is empty\n"); - } - else - { - printf("failure -> the tree is not empty\n"); - } - - if (!tree_delete(tree, 8)) - { - printf("success -> tree is empty, so delete failureed!\n"); - } - else - { - printf("failure -> tree is empty, but delete succeed!\n"); - } - - // ------------------------------------ - // insert again - for (i = 0; i < 10; i++) - { - tree_insert(tree, dat[i]); - } - printf("tree : "); - TREE_DISP(tree); - - for (i = 0; i < 10; i++) - { - if (tree_delete(tree, i)) - { - printf("del %d: ", i); - TREE_DISP(tree); - } - } - - if (tree_empty(tree)) - { - printf("success -> the tree is empty\n"); - } - else - { - printf("failure -> the tree is not empty\n"); - } - - tree_destroy(&tree); - if (!tree_insert(tree, dat[0])) - { - printf("success -> after tree destroyed, tree_insert failureed!\n"); - } - - if (!tree_get_min(tree, &tmp)) - { - printf("success -> after tree destroyed, tree_get_min failured!\n"); - } - - if (!tree_get_max(tree, &tmp)) - { - printf("success -> after tree destroyed, tree_get_max failured!\n"); - } - - printf("----------------------------------------\n"); -} - - -#else - -#define TREE_DISP_DEPTH_PRE(tree) {tree_traversal_depth_preorder(tree,tree_data_display);printf("\n");} -#define TREE_DISP_DEPTH_IN(tree) {tree_traversal_depth_inorder(tree,tree_data_display);printf("\n");} -#define TREE_DISP_DEPTH_POST(tree) {tree_traversal_depth_postorder(tree,tree_data_display);printf("\n");} -#define TREE_DISP_BREADTH(tree) {tree_traversal_breadth(tree,tree_data_display);printf("\n");} - -// tree display -#define TREE_DISP(tree) TREE_DISP_DEPTH_IN(tree) - -void tree_test(void) -{ - int32_t i = 0; - // tree_data_t dat[10] = {5,0,2,4,3,1,8,7,9,6}; // debug data - tree_data_t dat[10] = {0,1,2,3,4,5,6,7,8,9}; // test data1 - // tree_data_t dat[10] = { 3,1,2,5,4,8,6,7,9,0 }; // test data2 - tree_data_t tmp; - ptree_t tree = NULL; - - tree_init(&tree); - - for (i = 0; i < 10; i++) - { - tree_insert(tree, dat[i]); - } - printf("tree : "); - TREE_DISP(tree); - - tree_get_min(tree, &tmp); - if(tmp == 0) - { - printf("success -> tree_get_min is %d\n",tmp); - } - else - { - printf("failure -> tree_get_min is %d ?\n", tmp); - } - - tree_get_max(tree, &tmp); - if (tmp == 9) - { - printf("success -> tree_get_max is %d\n", tmp); - } - else - { - printf("failure -> tree_get_max is %d ?\n", tmp); - } - - // delete the root - tree_delete(tree, 5); - printf("del %d: ", 5); - TREE_DISP(tree); - - // delete the leaf - tree_delete(tree, 3); - printf("del %d: ", 3); - TREE_DISP(tree); - - // delete the node which has two nodes - tree_delete(tree, 8); - printf("del %d: ", 8); - TREE_DISP(tree); - - tree_clear(tree); - printf("success -> tree_clear success!\n"); - if (tree_empty(tree)) - { - printf("success -> the tree is empty\n"); - } - else - { - printf("failure -> the tree is not empty\n"); - } - - if (!tree_delete(tree, 8)) - { - printf("success -> tree is empty, so delete failureed!\n"); - } - else - { - printf("failure -> tree is empty, but delete succeed!\n"); - } - - // ------------------------------------ - // insert again - for (i = 0; i < 10; i++) - { - tree_insert(tree, dat[i]); - } - printf("tree : "); - TREE_DISP(tree); - - for (i = 0; i < 10; i++) - { - if (tree_delete(tree, i)) - { - printf("del %d: ", i); - TREE_DISP(tree); - } - } - - if (tree_empty(tree)) - { - printf("success -> the tree is empty\n"); - } - else - { - printf("failure -> the tree is not empty\n"); - } - - tree_destroy(&tree); - if (!tree_insert(tree, dat[0])) - { - printf("success -> after tree destroyed, tree_insert failureed!\n"); - } - - if(!tree_get_min(tree,&tmp)) - { - printf("success -> after tree destroyed, tree_get_min failured!\n"); - } - - if(!tree_get_max(tree,&tmp)) - { - printf("success -> after tree destroyed, tree_get_max failured!\n"); - } - - printf("----------------------------------------\n"); -} -#endif -#endif - /** * @brief * int data[] = { 5,2,3,1,7,8,6 }; @@ -276,7 +10,7 @@ void tree_test(void) * | | | | * 1 3 6 8 */ -void test_tree_num(void) +void test_avltree_num(void) { uint32_t i = 0; // int data[] = { 2,1,3,4}; @@ -291,7 +25,7 @@ void test_tree_num(void) tree->print_obj = print_num; tree->compare = compare_num; - printf("\n\n----- test_tree_num -----\n"); + printf("\n\n----- test_avltree_num -----\n"); printf("----- insert -----\n"); for (i = 0; i < len; i++) @@ -392,7 +126,129 @@ void test_tree_num(void) tree_free(tree); } + + +/** + * @brief + */ +void test_rbtree_num(void) +{ + uint32_t i = 0; + // int data[] = { 2,1,3,4}; + // int data[] = { 1,2,3,4,5,6}; + // int data[] = { 5,2,3,1,7,8,6 }; + int data[] = { 5,2,3,1,7,8,6,4,9,10,12,11,15,14,13 }; + int temp = 0; + uint32_t len = sizeof(data) / sizeof(data[0]); + + tree_t tree = tree_new(); + tree_rb_init(tree, sizeof(int)); + tree->print_obj = print_num; + tree->compare = compare_num; + + printf("\n\n----- test_rbtree_num -----\n"); + + printf("----- insert -----\n"); + for (i = 0; i < len; i++) + { + temp = data[i]; + tree->insert(tree, &temp); + + printf("insert = "); + tree->print_obj(&temp); + printf("size = %2d : ", tree->size(tree)); + tree->preorder(tree, tree->_root); + printf("\n"); + } + + printf("----- max -----\n"); + tree->max(tree, &temp); + tree->print_obj(&temp); + printf("\n"); + + printf("----- min -----\n"); + tree->min(tree, &temp); + tree->print_obj(&temp); + printf("\n"); + + printf("----- tree -----\n"); + tree->clear(tree); + if(tree->empty(tree)) + { + printf("----- empty -----\n"); + } + printf("----- insert -----\n"); + for (i = 0; i < len; i++) + { + temp = data[i]; + tree->insert(tree, &temp); + } + + printf("----- preorder -----\n"); + tree->preorder(tree, tree->_root); + printf("\n"); + + printf("----- inorder -----\n"); + tree->inorder(tree, tree->_root); + printf("\n"); + + printf("----- postorder -----\n"); + tree->postorder(tree, tree->_root); + printf("\n"); + + printf("----- breadth -----\n"); + tree->breadth(tree, tree->_root); + printf("\n"); + + printf("----- right priority -----\n"); + tree->order(tree, true); + + printf("----- preorder(right) -----\n"); + tree->preorder(tree, tree->_root); + printf("\n"); + + printf("----- inorder(right) -----\n"); + tree->inorder(tree, tree->_root); + printf("\n"); + + printf("----- postorder(right) -----\n"); + tree->postorder(tree, tree->_root); + printf("\n"); + + printf("----- breadth(right) -----\n"); + tree->breadth(tree, tree->_root); + printf("\n"); + +#if 0 + printf("----- left priority -----\n"); + tree->order(tree, false); + printf("----- preorder -----\n"); + tree->preorder(tree, tree->_root); + printf("\n"); + + for (i = 0; i < len; i++) + { + temp = data[i]; + // delete + tree->delete(tree, &temp); + + printf("delete = "); + tree->print_obj(&temp); + printf("size = %2d : ", tree->size(tree)); + tree->preorder(tree, tree->_root); + printf("\n"); + } + + if(tree->empty(tree)) + { + printf("----- empty -----\n"); + } +#endif + tree_free(tree); +} + void test_tree(void) { - test_tree_num(); + test_avltree_num(); + // test_rbtree_num(); }