Basic working red black tree
This commit is contained in:
parent
12388ac8f6
commit
ce1877f52a
32
include/tree.h
Normal file
32
include/tree.h
Normal file
@ -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
|
||||||
443
src/tree.c
Normal file
443
src/tree.c
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user