From ce1877f52a1b65ca515acb12ceeda8250b79e70e Mon Sep 17 00:00:00 2001 From: rexy712 Date: Sun, 12 Jan 2020 00:18:45 -0800 Subject: [PATCH] Basic working red black tree --- include/tree.h | 32 ++++ src/tree.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 475 insertions(+) create mode 100644 include/tree.h create mode 100644 src/tree.c diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000..313a72c --- /dev/null +++ b/include/tree.h @@ -0,0 +1,32 @@ +#ifndef RJP_TREE_H +#define RJP_TREE_H + +#include "rjp.h" + +#define RJP_TREE_SUCCESS 0 +#define RJP_TREE_ERR_NULL_ROOT 1 +#define RJP_TREE_ERR_NOT_FOUND 2 + +typedef struct RJP_object_member{ + RJP_string name; + RJP_value value; +}RJP_object_member; + +struct RJP_tree_node; +typedef struct RJP_tree_node RJP_tree_node; +struct RJP_tree_node{ + RJP_tree_node* parent; + RJP_tree_node* left; + RJP_tree_node* right; + RJP_object_member data; + unsigned color:1; +}; + +RJP_tree_node* irjp_new_node(RJP_object_member value); +RJP_tree_node* irjp_insert_value(RJP_tree_node* root, RJP_object_member value, int* status); +RJP_tree_node* irjp_remove_value(RJP_tree_node* root, RJP_object_member value, int* status); +RJP_tree_node* irjp_search_value(RJP_tree_node* root, RJP_object_member value); +void irjp_dbg_print_tree(RJP_tree_node* root); +void irjp_dbg_print_tree_bfs(RJP_tree_node* root); + +#endif diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..00dad9b --- /dev/null +++ b/src/tree.c @@ -0,0 +1,443 @@ +#include "tree.h" + +#include +#include +#include + +#define BLACK 0 +#define RED 1 + + +//TMP +#define rjp_malloc malloc +#define rjp_free free +#define rjp_free_value(x) + +static RJP_tree_node* irjp_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode); +static RJP_tree_node* irjp_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode); +static RJP_tree_node* irjp_repair_tree(RJP_tree_node* node); +static void irjp_copy_node(RJP_tree_node *restrict dest, RJP_tree_node *restrict src); +static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restrict child); +static void irjp_delete_node(RJP_tree_node* node); +static RJP_tree_node* irjp_remove_node(RJP_tree_node* target); + +static inline RJP_tree_node* irjp_grandparent(RJP_tree_node* n){ + if(!n->parent) + return NULL; + return n->parent->parent; +} +static inline RJP_tree_node* irjp_sibling(RJP_tree_node* n){ + RJP_tree_node* p = n->parent; + if(!p) + return NULL; + if(p->left == n) + return p->right; + return p->left; +} +static inline RJP_tree_node* irjp_uncle(RJP_tree_node* n){ + if(!n->parent) + return NULL; + return irjp_sibling(n->parent); +} +static inline RJP_tree_node* irjp_rotate_right(RJP_tree_node* pivot){ + RJP_tree_node* newroot = pivot->left; + pivot->left = newroot->right; + newroot->right = pivot; + newroot->parent = pivot->parent; + pivot->parent = newroot; + if(newroot->parent){ + if(newroot->parent->left == pivot) + newroot->parent->left = newroot; + else + newroot->parent->right = newroot; + } + if(pivot->left) + pivot->left->parent = pivot; + return newroot; +} +static inline RJP_tree_node* irjp_rotate_left(RJP_tree_node* pivot){ + RJP_tree_node* newroot = pivot->right; + pivot->right = newroot->left; + newroot->left = pivot; + newroot->parent = pivot->parent; + pivot->parent = newroot; + if(newroot->parent){ + if(newroot->parent->left == pivot) + newroot->parent->left = newroot; + else + newroot->parent->right = newroot; + } + if(pivot->right) + pivot->right->parent = pivot; + return newroot; +} +static inline int irjp_is_inside_left(RJP_tree_node* n){ + RJP_tree_node* p = n->parent; + RJP_tree_node* g = irjp_grandparent(n); + return n == p->right && p == g->left; +} +static inline int irjp_is_inside_right(RJP_tree_node* n){ + RJP_tree_node* p = n->parent; + RJP_tree_node* g = irjp_grandparent(n); + return n == p->left && p == g->right; +} +static void irjp_copy_node(RJP_tree_node *restrict dest, RJP_tree_node *restrict src){ + dest->data = src->data; +} +static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restrict child){ + if(child) + child->parent = node->parent; + if(!node->parent) + return; + if(node == node->parent->left) + node->parent->left = child; + else + node->parent->right = child; +} +static void irjp_delete_node(RJP_tree_node* node){ + rjp_free(node->data.name.value); + rjp_free_value(&node->data.value); + rjp_free(node); +} + +RJP_tree_node* irjp_new_node(RJP_object_member value){ + RJP_tree_node* node = rjp_malloc(sizeof(RJP_tree_node)); + node->data.name = value.name; + node->data.value = value.value; + node->parent = node->left = node->right = NULL; + return node; +} +RJP_tree_node* irjp_insert_value(RJP_tree_node* root, RJP_object_member value, int* status){ + *status = RJP_TREE_SUCCESS; + if(!root){ + root = irjp_new_node(value); + return root; + } + return irjp_insert_node(root, irjp_new_node(value)); +} +static RJP_tree_node* irjp_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){ + irjp_insert_impl(root, newnode); + irjp_repair_tree(newnode); + while(root->parent) + root = root->parent; + return root; +} +static RJP_tree_node* irjp_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){ + if(!root){ + return newnode; + } + RJP_tree_node* n = root; + while(1){ + //compare json key strings + int cmpval = strcmp(newnode->data.name.value, n->data.name.value); + if(cmpval < 0){ + if(n->left){ + n = n->left; + }else{ + n->left = newnode; + newnode->parent = n; + break; + } + }else{ + if(n->right){ + n = n->right; + }else{ + n->right = newnode; + newnode->parent = n; + break; + } + } + } + return newnode; +} +static RJP_tree_node* irjp_repair_tree(RJP_tree_node* node){ + node->color = RED; + while(1){ + if(!node->parent){ + node->color = BLACK; + return node; + }else if(node->parent->color == BLACK){ + return node; + }else if(irjp_uncle(node) && irjp_uncle(node)->color == RED){ + node->parent->color = BLACK; + irjp_uncle(node)->color = BLACK; + node = irjp_grandparent(node); + }else{ + if(irjp_is_inside_left(node)){ + irjp_rotate_left(node->parent); + node = node->left; + }else if(irjp_is_inside_right(node)){ + irjp_rotate_right(node->parent); + node = node->right; + } + RJP_tree_node* pa = node->parent; + RJP_tree_node* gp = irjp_grandparent(node); + if(node == pa->left){ + irjp_rotate_right(gp); + }else{ + irjp_rotate_left(gp); + } + pa->color = BLACK; + gp->color = RED; + return node; + } + } +} + +RJP_tree_node* irjp_search_value(RJP_tree_node* root, RJP_object_member value){ + while(root != NULL){ + int cmpval = strcmp(value.name.value, root->data.name.value); + if(cmpval < 0){ + root = root->left; + }else if(cmpval > 0){ + root = root->right; + }else{ + return root; + } + } + return NULL; +} +void irjp_dbg_print_tree(RJP_tree_node* root){ + if(!root){ + return; + } + RJP_tree_node* current = root, *pre; + while(current){ + if(!current->left){ + printf("%s\n", current->data.name.value); + current = current->right; + }else{ + pre = current->left; + while(pre->right && pre->right != current){ + pre = pre->right; + } + if(!pre->right){ + pre->right = current; + current = current->left; + }else{ + pre->right = NULL; + printf("%s\n", current->data.name.value); + current = current->right; + } + } + } +} +#define pop() front = (front+1)%queuelen +#define push(val, dp) do{queue[rear].n = (val);queue[rear].depth = (dp);rear = (rear+1)%queuelen;}while(0) +struct tmpthing{ + RJP_tree_node* n; + int depth; +}; + +void irjp_dbg_print_tree_bfs(RJP_tree_node* root){ + int queuelen = 64; + struct tmpthing queue[64]; + int front = 0, rear = 0; + int lastdepth = 0; + + push(root, lastdepth); + while(front != rear){ + if(lastdepth != queue[front].depth){ + lastdepth = queue[front].depth; + printf("\n"); + } + if(!queue[front].n){ + printf("*"); + }else{ + printf("%s ", queue[front].n->data.name.value); + if(queue[front].n->left){ + push(queue[front].n->left, queue[front].depth+1); + }else{ + push(NULL,queue[front].depth+1); + } + if(queue[front].n->right){ + push(queue[front].n->right, queue[front].depth+1); + }else{ + push(NULL,queue[front].depth+1); + } + } + pop(); + } + printf("\n"); +} + +RJP_tree_node* irjp_remove_value(RJP_tree_node* root, RJP_object_member value, int* status){ + if(!root){ + *status = RJP_TREE_ERR_NULL_ROOT; + return root; + } + RJP_tree_node* n = irjp_search_value(root, value); + if(!n){ + *status = RJP_TREE_ERR_NOT_FOUND; + return root; + } + *status = RJP_TREE_SUCCESS; + return irjp_remove_node(n); +} +static RJP_tree_node* irjp_remove_node(RJP_tree_node* target){ + while(target->right && target->left){ + irjp_copy_node(target, target->right); + target = target->right; + } + RJP_tree_node* retval = target->parent; + RJP_tree_node* to_delete = target; + + RJP_tree_node* child = (target->left) ? target->left : target->right; + + do{ + //handle trivial cases + if(target->color == RED || child){ + if(child) + child->color = BLACK; + irjp_replace_node(target, child); + if(!target->parent) + retval = child; + break; + }else if(!target->parent){ + break; + + //handle harder cases + }else{ + //parent and sibling guaranteed to exist at this point + RJP_tree_node* sibling = irjp_sibling(target); + + //Deal with red sibling + if(sibling->color == RED){ + sibling->color = BLACK; + target->parent->color = RED; + if(target == target->parent->left){ + irjp_rotate_left(target->parent); + }else{ + irjp_rotate_right(target->parent); + } + sibling = irjp_sibling(target); + } + + //sibling guaranteed to be black here + if(target->parent->color == BLACK && + ((!sibling->left) || sibling->left->color == BLACK) && + ((!sibling->right) || sibling->right->color == BLACK)) + { + sibling->color = RED; + target = target->parent; + continue; + } + + //sibling guaranteed to be black here + if(target->parent->color == RED && + ((!sibling->left) || sibling->left->color == BLACK) && + ((!sibling->right) || sibling->right->color == BLACK)) + { + sibling->color = RED; + target->parent->color = BLACK; + break; + } + + //Orient the subtree for the following section + if((target == target->parent->left) && (!sibling->right || sibling->right->color == BLACK) && + (sibling->left && sibling->left->color == RED)) + { + sibling->color = RED; + if(sibling->left) + sibling->left->color = BLACK; + irjp_rotate_right(sibling); + sibling = irjp_sibling(target); + }else if((target == target->parent->right) && (sibling->right && sibling->right->color == RED) && + (!sibling->left || sibling->left->color == BLACK)) + { + sibling->color = RED; + if(sibling->right) + sibling->right->color = BLACK; + irjp_rotate_left(sibling); + sibling = irjp_sibling(target); + } + + sibling->color = target->parent->color; + target->parent->color = BLACK; + if(target == target->parent->left){ + //guaranteed to not be NULL + sibling->right->color = BLACK; + irjp_rotate_left(target->parent); + }else{ + //guaranteed to not be NULL + sibling->left->color = BLACK; + irjp_rotate_right(target->parent); + } + break; + } + }while(1); + + irjp_replace_node(to_delete, NULL); + to_delete->data.name.value = NULL; + to_delete->data.value.type = rjp_json_null; + irjp_delete_node(to_delete); + + //return new root + if(!retval) + return NULL; + while(retval->parent) + retval = retval->parent; + return retval; +} +/*void irjp_handle_del_with_red_sibling(RJP_tree_node* n){ + RJP_tree_node* sibling = irjp_sibling(n); + if(s->color == RED){ + sibling->color = BLACK; + n->parent->color = RED; + if(target == parent->left) + irjp_rotate_left(parent); + else + irjp_rotate_right(parent); + }else{ + irjp_handle_del_with_black_parent_sibling_niblings(n); + } +void irjp_handle_del_with_black_parent_sibling_niblings(RJP_tree_node* n){ + RJP_tree_node* sibling = irjp_sibling(n); + if(n->parent->color == BLACK && sibling->color == BLACK && + ((!sibling->left) || sibling->left->color == BLACK) && + ((!sibling->right) || sibling->right->color == BLACK) + { + sibling->color = RED; + irjp_handle_del_root(n->parent); + }else{ + irjp_handle_del_with_black_sibling_niblings_red_parent(n); + } +} +void irjp_handle_del_with_black_sibling_niblings_red_parent(RJP_tree_node* n){ + RJP_tree_node* sibling = irjp_sibling(n); + if(n->parent->color == RED && sibling->color == BLACK && + ((!sibling->left) || sibling->left->color == BLACK) && + ((!sibling->right) || sibling->right->color == BLACK) + { + sibling->color = RED; + n->parent->color = BLACK; + }else{ + irjp_handle_del_with_black_sibling_rnibling_black_lnibling(n); + } +} +void irjp_handle_del_with_black_sibling_rnibling_black_lnibling(RJP_tree_node* n){ + RJP_tree_node* sibling = irjp_sibling(n); + if((n == n->parent->left) && (sibling->right->color == BLACK) && (sibling->left->color == RED)){ + sibling->color = RED; + s->left->color = BLACK; + irjp_rotate_right(sibling); + }else if((n == n->parent->right) && (sibling->right->color == RED) && (sibling->left->color == BLACK)){ + sibling->color = RED; + s->right->color = BLACK; + irjp_rotate_left(sibling); + } + irjp_handle_del_with_black_sibling_lnibling_black_rnibling_red(n); +} +void irjp_handle_del_with_black_sibling_lnibling_black_rnibling_red(RJP_tree_node* n){ + RJP_tree_node* sibling = irjp_sibling(n); + sibling->color = n->parent->color; + n->parent->color = BLACK; + if(n == n->parent->left){ + sibling->right->color = BLACK; + irjp_rotate_left(n->parent); + }else{ + sibling->left->color = BLACK; + irjp_rotate_right(n->parent); + } +}*/ +