rbtree
diff src/rbtree.c @ 0:6621337b6378
red-black tree lib
author | John Tsiombikas <nuclear@mutantstargoat.com> |
---|---|
date | Sun, 09 Oct 2011 07:48:14 +0300 |
parents | |
children | 53afe96233f2 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/rbtree.c Sun Oct 09 07:48:14 2011 +0300 1.3 @@ -0,0 +1,456 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include "rbtree.h" 1.8 + 1.9 +#define INT2PTR(x) ((void*)(x)) 1.10 +#define PTR2INT(x) ((int)(x)) 1.11 + 1.12 +struct rbtree { 1.13 + struct rbnode *root; 1.14 + 1.15 + rb_alloc_func_t alloc; 1.16 + rb_free_func_t free; 1.17 + 1.18 + rb_cmp_func_t cmp; 1.19 + rb_del_func_t del; 1.20 + void *del_cls; 1.21 + 1.22 + struct rbnode *rstack, *iter; 1.23 +}; 1.24 + 1.25 +static int cmpaddr(void *ap, void *bp); 1.26 +static int cmpint(void *ap, void *bp); 1.27 + 1.28 +static int count_nodes(struct rbnode *node); 1.29 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); 1.30 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); 1.31 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); 1.32 +static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key); 1.33 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); 1.34 + 1.35 +struct rbtree *rb_create(rb_cmp_func_t cmp_func) 1.36 +{ 1.37 + struct rbtree *rb; 1.38 + 1.39 + if(!(rb = malloc(sizeof *rb))) { 1.40 + return 0; 1.41 + } 1.42 + if(rb_init(rb, cmp_func) == -1) { 1.43 + free(rb); 1.44 + return 0; 1.45 + } 1.46 + return rb; 1.47 +} 1.48 + 1.49 +void rb_free(struct rbtree *rb) 1.50 +{ 1.51 + rb_destroy(rb); 1.52 + free(rb); 1.53 +} 1.54 + 1.55 + 1.56 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) 1.57 +{ 1.58 + memset(rb, 0, sizeof *rb); 1.59 + 1.60 + if(cmp_func == RB_KEY_INT) { 1.61 + rb->cmp = cmpint; 1.62 + } else if(cmp_func == RB_KEY_STRING) { 1.63 + rb->cmp = (rb_cmp_func_t)strcmp; 1.64 + } else { 1.65 + rb->cmp = cmpaddr; 1.66 + } 1.67 + 1.68 + rb->alloc = malloc; 1.69 + rb->free = free; 1.70 + return 0; 1.71 +} 1.72 + 1.73 +void rb_destroy(struct rbtree *rb) 1.74 +{ 1.75 + del_tree(rb->root, rb->del, rb->del_cls); 1.76 +} 1.77 + 1.78 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) 1.79 +{ 1.80 + rb->alloc = alloc; 1.81 + rb->free = free; 1.82 +} 1.83 + 1.84 + 1.85 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) 1.86 +{ 1.87 + rb->cmp = func; 1.88 +} 1.89 + 1.90 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) 1.91 +{ 1.92 + rb->del = func; 1.93 + rb->del_cls = cls; 1.94 +} 1.95 + 1.96 +int rb_size(struct rbtree *rb) 1.97 +{ 1.98 + return count_nodes(rb->root); 1.99 +} 1.100 + 1.101 +int rb_insert(struct rbtree *rb, void *key, void *data) 1.102 +{ 1.103 + rb->root = insert(rb, rb->root, key, data); 1.104 + rb->root->red = 0; 1.105 + return 0; 1.106 +} 1.107 + 1.108 +int rb_inserti(struct rbtree *rb, int key, void *data) 1.109 +{ 1.110 + rb->root = insert(rb, rb->root, INT2PTR(key), data); 1.111 + rb->root->red = 0; 1.112 + return 0; 1.113 +} 1.114 + 1.115 + 1.116 +int rb_delete(struct rbtree *rb, void *key) 1.117 +{ 1.118 + rb->root = delete(rb, rb->root, key); 1.119 + rb->root->red = 0; 1.120 + return 0; 1.121 +} 1.122 + 1.123 +int rb_deletei(struct rbtree *rb, int key) 1.124 +{ 1.125 + rb->root = delete(rb, rb->root, INT2PTR(key)); 1.126 + rb->root->red = 0; 1.127 + return 0; 1.128 +} 1.129 + 1.130 + 1.131 +void *rb_find(struct rbtree *rb, void *key) 1.132 +{ 1.133 + return find(rb, rb->root, key); 1.134 +} 1.135 + 1.136 +void *rb_findi(struct rbtree *rb, int key) 1.137 +{ 1.138 + return find(rb, rb->root, INT2PTR(key)); 1.139 +} 1.140 + 1.141 + 1.142 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) 1.143 +{ 1.144 + traverse(rb->root, func, cls); 1.145 +} 1.146 + 1.147 + 1.148 +struct rbnode *rb_root(struct rbtree *rb) 1.149 +{ 1.150 + return rb->root; 1.151 +} 1.152 + 1.153 +void rb_begin(struct rbtree *rb) 1.154 +{ 1.155 + rb->rstack = 0; 1.156 + rb->iter = rb->root; 1.157 +} 1.158 + 1.159 +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) 1.160 +#define pop(sp) ((sp) = (sp)->next) 1.161 +#define top(sp) (sp) 1.162 + 1.163 +struct rbnode *rb_next(struct rbtree *rb) 1.164 +{ 1.165 + struct rbnode *res = 0; 1.166 + 1.167 + while(rb->rstack || rb->iter) { 1.168 + if(rb->iter) { 1.169 + push(rb->rstack, rb->iter); 1.170 + rb->iter = rb->iter->left; 1.171 + } else { 1.172 + rb->iter = top(rb->rstack); 1.173 + pop(rb->rstack); 1.174 + res = rb->iter; 1.175 + rb->iter = rb->iter->right; 1.176 + break; 1.177 + } 1.178 + } 1.179 + return res; 1.180 +} 1.181 + 1.182 +void *rb_node_key(struct rbnode *node) 1.183 +{ 1.184 + return node ? node->key : 0; 1.185 +} 1.186 + 1.187 +int rb_node_keyi(struct rbnode *node) 1.188 +{ 1.189 + return node ? PTR2INT(node->key) : 0; 1.190 +} 1.191 + 1.192 +void *rb_node_data(struct rbnode *node) 1.193 +{ 1.194 + return node ? node->data : 0; 1.195 +} 1.196 + 1.197 +static int cmpaddr(void *ap, void *bp) 1.198 +{ 1.199 + return ap < bp ? -1 : (ap > bp ? 1 : 0); 1.200 +} 1.201 + 1.202 +static int cmpint(void *ap, void *bp) 1.203 +{ 1.204 + return PTR2INT(ap) - PTR2INT(bp); 1.205 +} 1.206 + 1.207 + 1.208 +/* ---- left-leaning 2-3 red-black implementation ---- */ 1.209 + 1.210 +/* helper prototypes */ 1.211 +static int is_red(struct rbnode *tree); 1.212 +static void color_flip(struct rbnode *tree); 1.213 +static struct rbnode *rot_left(struct rbnode *a); 1.214 +static struct rbnode *rot_right(struct rbnode *a); 1.215 +static struct rbnode *find_min(struct rbnode *tree); 1.216 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); 1.217 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ 1.218 +static struct rbnode *move_red_left(struct rbnode *tree); 1.219 +static struct rbnode *fix_up(struct rbnode *tree); 1.220 + 1.221 +static int count_nodes(struct rbnode *node) 1.222 +{ 1.223 + if(!node) 1.224 + return 0; 1.225 + 1.226 + return 1 + count_nodes(node->left) + count_nodes(node->right); 1.227 +} 1.228 + 1.229 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) 1.230 +{ 1.231 + if(!node) 1.232 + return; 1.233 + 1.234 + del_tree(node->left, delfunc, cls); 1.235 + del_tree(node->right, delfunc, cls); 1.236 + 1.237 + delfunc(node, cls); 1.238 + free(node); 1.239 +} 1.240 + 1.241 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) 1.242 +{ 1.243 + int cmp; 1.244 + 1.245 + if(!tree) { 1.246 + struct rbnode *node = rb->alloc(sizeof *node); 1.247 + node->red = 1; 1.248 + node->key = key; 1.249 + node->data = data; 1.250 + node->left = node->right = 0; 1.251 + return node; 1.252 + } 1.253 + 1.254 + cmp = rb->cmp(key, tree->key); 1.255 + 1.256 + if(cmp < 0) { 1.257 + tree->left = insert(rb, tree->left, key, data); 1.258 + } else if(cmp > 0) { 1.259 + tree->right = insert(rb, tree->right, key, data); 1.260 + } else { 1.261 + tree->data = data; 1.262 + } 1.263 + 1.264 + /* fix right-leaning reds */ 1.265 + if(is_red(tree->right)) { 1.266 + tree = rot_left(tree); 1.267 + } 1.268 + /* fix two reds in a row */ 1.269 + if(is_red(tree->left) && is_red(tree->left->left)) { 1.270 + tree = rot_right(tree); 1.271 + } 1.272 + 1.273 + /* if 4-node, split it by color inversion */ 1.274 + if(is_red(tree->left) && is_red(tree->right)) { 1.275 + color_flip(tree); 1.276 + } 1.277 + 1.278 + return tree; 1.279 +} 1.280 + 1.281 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) 1.282 +{ 1.283 + int cmp; 1.284 + 1.285 + if(!tree) { 1.286 + return 0; 1.287 + } 1.288 + 1.289 + cmp = rb->cmp(key, tree->key); 1.290 + 1.291 + if(cmp < 0) { 1.292 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 1.293 + tree = move_red_left(tree); 1.294 + } 1.295 + tree->left = delete(rb, tree->left, key); 1.296 + } else { 1.297 + /* need reds on the right */ 1.298 + if(is_red(tree->left)) { 1.299 + tree = rot_right(tree); 1.300 + } 1.301 + 1.302 + /* found it at the bottom (XXX what certifies left is null?) */ 1.303 + if(cmp == 0 && !tree->right) { 1.304 + if(rb->del) { 1.305 + rb->del(tree, rb->del_cls); 1.306 + } 1.307 + rb->free(tree); 1.308 + return 0; 1.309 + } 1.310 + 1.311 + if(!is_red(tree->right) && !is_red(tree->right->left)) { 1.312 + tree = move_red_left(tree); 1.313 + } 1.314 + 1.315 + if(key == tree->key) { 1.316 + struct rbnode *rmin = find_min(tree->right); 1.317 + tree->key = rmin->key; 1.318 + tree->data = rmin->data; 1.319 + tree->right = del_min(rb, tree->right); 1.320 + } else { 1.321 + tree->right = delete(rb, tree->right, key); 1.322 + } 1.323 + } 1.324 + 1.325 + return fix_up(tree); 1.326 +} 1.327 + 1.328 +static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) 1.329 +{ 1.330 + int cmp; 1.331 + 1.332 + if(!node) 1.333 + return 0; 1.334 + 1.335 + if((cmp = rb->cmp(key, node->key)) == 0) { 1.336 + return node; 1.337 + } 1.338 + return find(rb, cmp < 0 ? node->left : node->right, key); 1.339 +} 1.340 + 1.341 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) 1.342 +{ 1.343 + if(!node) 1.344 + return; 1.345 + 1.346 + traverse(node->left, func, cls); 1.347 + func(node, cls); 1.348 + traverse(node->right, func, cls); 1.349 +} 1.350 + 1.351 +/* helpers */ 1.352 + 1.353 +static int is_red(struct rbnode *tree) 1.354 +{ 1.355 + return tree && tree->red; 1.356 +} 1.357 + 1.358 +static void color_flip(struct rbnode *tree) 1.359 +{ 1.360 + tree->red = !tree->red; 1.361 + tree->left->red = !tree->left->red; 1.362 + tree->right->red = !tree->right->red; 1.363 +} 1.364 + 1.365 +static struct rbnode *rot_left(struct rbnode *a) 1.366 +{ 1.367 + struct rbnode *b = a->right; 1.368 + a->right = b->left; 1.369 + b->left = a; 1.370 + b->red = a->red; 1.371 + a->red = 1; 1.372 + return b; 1.373 +} 1.374 + 1.375 +static struct rbnode *rot_right(struct rbnode *a) 1.376 +{ 1.377 + struct rbnode *b = a->left; 1.378 + a->left = b->right; 1.379 + b->right = a; 1.380 + b->red = a->red; 1.381 + a->red = 1; 1.382 + return b; 1.383 +} 1.384 + 1.385 +static struct rbnode *find_min(struct rbnode *tree) 1.386 +{ 1.387 + if(!tree || !tree->left) { 1.388 + return tree; 1.389 + } 1.390 + return find_min(tree->left); 1.391 +} 1.392 + 1.393 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) 1.394 +{ 1.395 + if(!tree->left) { 1.396 + if(rb->del) { 1.397 + rb->del(tree->left, rb->del_cls); 1.398 + } 1.399 + rb->free(tree->left); 1.400 + return 0; 1.401 + } 1.402 + 1.403 + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ 1.404 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 1.405 + tree = move_red_left(tree); 1.406 + } 1.407 + tree->left = del_min(rb, tree->left); 1.408 + 1.409 + /* fix right-reds, red-reds, and split 4-nodes on the way up */ 1.410 + return fix_up(tree); 1.411 +} 1.412 + 1.413 +#if 0 1.414 +/* push a red link on this node to the right */ 1.415 +static struct rbnode *move_red_right(struct rbnode *tree) 1.416 +{ 1.417 + /* flipping it makes both children go red, so we have a red to the right */ 1.418 + color_flip(tree); 1.419 + 1.420 + /* if after the flip we've got a red-red situation to the left, fix it */ 1.421 + if(is_red(tree->left->left)) { 1.422 + tree = rot_right(tree); 1.423 + color_flip(tree); 1.424 + } 1.425 + return tree; 1.426 +} 1.427 +#endif 1.428 + 1.429 +/* push a red link on this node to the left */ 1.430 +static struct rbnode *move_red_left(struct rbnode *tree) 1.431 +{ 1.432 + /* flipping it makes both children go red, so we have a red to the left */ 1.433 + color_flip(tree); 1.434 + 1.435 + /* if after the flip we've got a red-red on the right-left, fix it */ 1.436 + if(is_red(tree->right->left)) { 1.437 + tree->right = rot_right(tree->right); 1.438 + tree = rot_left(tree); 1.439 + color_flip(tree); 1.440 + } 1.441 + return tree; 1.442 +} 1.443 + 1.444 +static struct rbnode *fix_up(struct rbnode *tree) 1.445 +{ 1.446 + /* fix right-leaning */ 1.447 + if(is_red(tree->right)) { 1.448 + tree = rot_left(tree); 1.449 + } 1.450 + /* change invalid red-red pairs into a proper 4-node */ 1.451 + if(is_red(tree->left) && is_red(tree->left->left)) { 1.452 + tree = rot_right(tree); 1.453 + } 1.454 + /* split 4-nodes */ 1.455 + if(is_red(tree->left) && is_red(tree->right)) { 1.456 + color_flip(tree); 1.457 + } 1.458 + return tree; 1.459 +}