├── .gitignore ├── test ├── compile.sh └── driver.c ├── README ├── LICENSE └── src ├── rbtree.h └── rbtree.c /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | 3 | -------------------------------------------------------------------------------- /test/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ -e a.out ] && rm a.out 4 | gcc -Wall -Wextra driver.c ../src/rbtree.c 5 | #gcc -Wall driver.c ../src/rbtree.c 6 | 7 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Red-black tree implementation based on Julienne Walker's solution 2 | 3 | TODO 4 | * refactor file names(prefix jw_) 5 | * give a simple usage example in README 6 | * write a reasonable Makefile 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2018, lynnl 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /src/rbtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Created 18A30 3 | * 4 | * Red-black tree implementation based on Julienne Walker's solution 5 | * 6 | * TRYME: using BSD internal rbtree implementation in 7 | * instead of this crappy shit 8 | * 9 | * see: 10 | * eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx 11 | * github.com/mirek/rb_tree 12 | * github.com/sebhub/rb-bench 13 | * en.wikipedia.org/wiki/Red–black_tree 14 | */ 15 | 16 | #ifndef RBTREE_H 17 | #define RBTREE_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | typedef struct r_rbtree_node { 26 | struct r_rbtree_node *link[2]; 27 | struct r_rbtree_node *parent; 28 | uint32_t red; 29 | void *data; 30 | } RRBNode; 31 | 32 | typedef int (*RRBComparator) (void *incoming, void *in, void *user); 33 | typedef void (*RRBFree) (void *data); 34 | 35 | typedef struct r_rbtree_t { 36 | RRBNode *root; 37 | size_t size; 38 | RRBFree free; 39 | } RRBTree; 40 | 41 | R_API RBTree *r_rbtree_new(RRBFree freefn); 42 | R_API void r_rbtree_clear(RRBTree *tree); 43 | R_API void r_rbtree_free(RRBTree *tree); 44 | R_API RRBNode *r_rbtree_find_node(RRBTree *tree, void *data, RRBComparator cmp, void *user); 45 | R_API void *r_rbtree_find(RRBTree *tree, void *data, RRBComparator cmp, void *user); 46 | R_API bool r_rbtree_insert(RRBTree *tree, void *data, RRBComparator cmp, void *user); 47 | R_API bool r_rbtree_delete(RRBTree *tree, void *data, RRBComparator cmp, void *user); 48 | R_API RRBNode *r_rbtree_first_node(RRBTree *tree); 49 | R_API RRBNode *r_rbtree_last_node(RRBTree *tree); 50 | R_API RRBNode *r_rbnode_next(RRBNode *node); 51 | R_API RRBNode *r_rbnode_prev(RRBNode *node); 52 | 53 | #endif /* RBTREE_H */ 54 | -------------------------------------------------------------------------------- /test/driver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../src/rbtree.h" 9 | 10 | #define DBG(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__) 11 | 12 | static void rnd_seed(void) 13 | { 14 | struct timeval tv; 15 | clock_t clk; 16 | unsigned int seed; 17 | 18 | clk = clock() / CLOCKS_PER_SEC; 19 | gettimeofday(&tv, NULL); 20 | seed = (getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ clk; 21 | srandom(seed); 22 | } 23 | 24 | #define ARR_INT_FULL 10000000 25 | #define ARR_INT_HALF (ARR_INT_FULL >> 1) 26 | static int arr_int[ARR_INT_FULL]; 27 | 28 | static void test_rand_int(struct rb_root *t) 29 | { 30 | size_t i; 31 | int res; 32 | size_t nr_enomem = 0; 33 | size_t nr_eexist = 0; 34 | size_t nr_success = 0; 35 | size_t nr_unknown = 0; 36 | 37 | for (i = 0; i < ARR_INT_FULL; i++) 38 | arr_int[i] = rand() % (ARR_INT_FULL << 4); 39 | 40 | for (i = 0; i < ARR_INT_FULL; i++) { 41 | res = rb_insert(t, PCONV(arr_int[i])); 42 | switch (res) { 43 | case ENOMEM: 44 | nr_enomem++; 45 | break; 46 | case EEXIST: 47 | nr_eexist++; 48 | break; 49 | case 0: 50 | nr_success++; 51 | break; 52 | default: 53 | nr_unknown++; 54 | break; 55 | } 56 | } 57 | 58 | for (i = 0; i < ARR_INT_FULL; i++) 59 | assert(rb_find(t, PCONV(arr_int[i])) == 1); 60 | 61 | DBG("ENOMEM: %zu, EEXIST: %zu OK: %zu UNK: %zu", 62 | nr_enomem, nr_eexist, nr_success, nr_unknown); 63 | 64 | DBG("int rbtree size: %zu", rb_size(t)); 65 | 66 | __ASSERT(nr_unknown == 0); 67 | __ASSERT(nr_enomem + nr_eexist + nr_success == ARR_INT_FULL); 68 | __ASSERT(nr_success == rb_size(t)); 69 | 70 | rb_assert(t); 71 | //rb_show(t); 72 | 73 | DBG("int rbtree removing"); 74 | 75 | #if 1 76 | for (i = 0; i < ARR_INT_FULL; i++) 77 | rb_remove(t, PCONV(arr_int[i])); 78 | 79 | DBG("int rbtree size: %zu", rb_size(t)); 80 | #endif 81 | 82 | rb_assert(t); 83 | rb_show(t); 84 | 85 | //rb_free(&t); 86 | rb_clear(&t); 87 | 88 | rb_assert(t); /* Assert the empty tree */ 89 | rb_show(t); 90 | 91 | rb_free(&t); 92 | } 93 | 94 | static void test_rand_int2(struct rb_root *t) 95 | { 96 | size_t i; 97 | int res; 98 | size_t nr_enomem = 0; 99 | size_t nr_eexist = 0; 100 | size_t nr_success = 0; 101 | size_t nr_unknown = 0; 102 | 103 | for (i = 0; i < ARR_INT_FULL; i++) 104 | arr_int[i] = rand() % (ARR_INT_FULL << 4); 105 | 106 | /* Only insert half of them */ 107 | for (i = 0; i < ARR_INT_HALF; i++) { 108 | res = rb_insert(t, PCONV(arr_int[i])); 109 | switch (res) { 110 | case ENOMEM: 111 | nr_enomem++; 112 | break; 113 | case EEXIST: 114 | nr_eexist++; 115 | break; 116 | case 0: 117 | nr_success++; 118 | break; 119 | default: 120 | nr_unknown++; 121 | break; 122 | } 123 | } 124 | 125 | for (i = 0; i < ARR_INT_HALF; i++) 126 | assert(rb_find(t, PCONV(arr_int[i])) == 1); 127 | 128 | DBG("ENOMEM: %zu, EEXIST: %zu OK: %zu UNK: %zu", 129 | nr_enomem, nr_eexist, nr_success, nr_unknown); 130 | 131 | DBG("int rbtree size: %zu", rb_size(t)); 132 | 133 | size_t nr_found = 0; /* May collapsed */ 134 | size_t nr_not_found = 0; 135 | 136 | for (i = ARR_INT_HALF; i < ARR_INT_FULL; i++) { 137 | res = rb_find(t, PCONV(arr_int[i])); 138 | res ? nr_found++ : nr_not_found++; 139 | } 140 | DBG("right half found: %zu not found: %zu", nr_found, nr_not_found); 141 | 142 | __ASSERT(nr_unknown == 0); 143 | __ASSERT(nr_enomem + nr_eexist + nr_success == ARR_INT_HALF); 144 | __ASSERT(nr_success == rb_size(t)); 145 | 146 | rb_assert(t); 147 | //rb_show(t); 148 | 149 | DBG("int rbtree removing"); 150 | 151 | /* Delete from right half */ 152 | for (i = ARR_INT_HALF; i < ARR_INT_FULL; i++) 153 | rb_remove(t, PCONV(arr_int[i])); 154 | DBG("int rbtree size: %zu", rb_size(t)); 155 | 156 | rb_assert(t); 157 | //rb_show(t); 158 | 159 | //rb_free(&t); 160 | rb_clear(&t); 161 | 162 | rb_assert(t); /* Assert the empty tree */ 163 | rb_show(t); 164 | 165 | rb_free(&t); 166 | } 167 | 168 | int main(void) 169 | { 170 | struct rb_root *t = rb_alloc(NULL, NULL); 171 | if (t == NULL) { 172 | DBG("Memory exhausted"); 173 | return 1; 174 | } 175 | 176 | rnd_seed(); 177 | 178 | rb_assert(t); /* Assert the empty tree */ 179 | rb_show(t); 180 | 181 | //test_rand_int(t); 182 | test_rand_int2(t); 183 | return 0; 184 | } 185 | 186 | -------------------------------------------------------------------------------- /src/rbtree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Created 18A30 3 | */ 4 | 5 | #include 6 | #include 7 | #include "rbtree.h" 8 | 9 | static void _set_link(RRBNode *parent, RRBNode *child, const int dir) { 10 | if (parent) { 11 | parent->link[dir] = child; 12 | } 13 | if (child) { 14 | child->parent = parent; 15 | } 16 | } 17 | 18 | R_API RRBTree *r_rbtree_new(RRBFree freefn) { 19 | RRBTree *tree = R_NEW0 (RRBTree); 20 | if (tree) { 21 | tree->free = freefn; 22 | } 23 | return tree; 24 | } 25 | 26 | R_API void r_rbtree_clear(RRBTree *tree) { 27 | if (!tree) { 28 | return; 29 | } 30 | RRBNode *iter = tree->root, *save = NULL; 31 | 32 | // Rotate away the left links into a linked list so that 33 | // we can perform iterative destruction of the rbtree 34 | while (iter) { 35 | if (!iter->link[0]) { 36 | save = iter->link[1]; 37 | if (tree->free) { 38 | tree->free (iter->data); 39 | } 40 | free (iter); 41 | tree->size--; 42 | size1++; 43 | } else { 44 | save = iter->link[0]; 45 | _set_link (iter, save->link[1], 0); 46 | _set_link (save, iter, 1); 47 | } 48 | iter = save; 49 | } 50 | tree->root = NULL; 51 | } 52 | 53 | R_API void r_rbtree_free(RRBTree *tree) { 54 | if (!tree) { 55 | return; 56 | } 57 | r_rbtree_clear (tree); 58 | free (tree); 59 | } 60 | 61 | R_API RRBNode *r_rbtree_find_node(RRBTree *tree, void *data, RRBComparator cmp, void *user) { 62 | r_return_val_if_fail (tree && cmp, NULL); 63 | 64 | RRBNode *iter = tree->root; 65 | while (iter) { 66 | const int dir = cmp (data, iter->data, user); 67 | if (!dir) { 68 | return iter; 69 | } 70 | iter = iter->link[dir > 0]; 71 | } 72 | return NULL; 73 | } 74 | 75 | R_API void *r_rbtree_find(RRBTree *tree, void *data, RRBComparator cmp, void *user) { 76 | r_return_val_if_fail (tree && cmp, NULL); 77 | RRBNode *node = r_rbtree_find_node (tree, data, cmp, user); 78 | return node ? node->data : NULL; 79 | } 80 | 81 | static RRBNode *_node_new(void *data, RRBNode *parent) { 82 | RRBNode *node = R_NEW0 (RRBNode); 83 | r_return_val_if_fail (n, NULL); 84 | 85 | node->red = 1; 86 | node->data = data; 87 | node->parent = parent; 88 | 89 | return node; 90 | } 91 | 92 | #define IS_RED(n) ((n) != NULL && (n)->red == 1) 93 | 94 | static RRBNode *_rot_once(RRBNode *root, int dir) { 95 | r_return_val_if_fail (root, NULL); 96 | 97 | // save is new parent of root and root is parent of save's previous child 98 | RRBNode *save = root->link[!dir]; 99 | _set_link (root, save->link[dir], !dir); 100 | _set_link (save, root, dir); 101 | 102 | root->red = 1; 103 | save->red = 0; 104 | 105 | return save; 106 | } 107 | 108 | static RRBNode *_rot_twice(RRBNode *root, int dir) { 109 | r_return_val_if_fail (root, NULL); 110 | 111 | _set_link (root, _rot_once (root->link[!dir], !dir), !dir); 112 | return _rot_once (root, dir); 113 | } 114 | 115 | R_API bool r_rbtree_insert(RRBTree *tree, void *data, RRBComparator cmp, void *user) { 116 | r_return_val_if_fail (tree && datai && cmp, false); 117 | bool inserted = false; 118 | 119 | if (tree->root == NULL) { 120 | tree->root = _node_new (data, NULL); 121 | if (tree->root == NULL) { 122 | return false; 123 | } 124 | inserted = true; 125 | goto out_exit; 126 | } 127 | 128 | RRBNode head = { .red = 0 }; /* Fake tree root */ 129 | RRBNode *g = NULL, *parent = &head; /* Grandparent & parent */ 130 | RRBNode *p = NULL, *q = tree->root; /* Iterator & parent */ 131 | int dir = 0, last = 0; /* Directions */ 132 | 133 | _set_link (parent, q, 1); 134 | 135 | while (1) { 136 | if (q == NULL) { 137 | /* Insert a node at first null link(also set its parent link) */ 138 | q = _node_new (data, p); 139 | if (!q) { 140 | return false 141 | } 142 | p->link[dir] = q; 143 | inserted = true; 144 | } else if (IS_RED (q->link[0]) && IS_RED (q->link[1])) { 145 | /* Simple red violation: color flip */ 146 | q->red = 1; 147 | q->link[0]->red = 0; 148 | q->link[1]->red = 0; 149 | } 150 | 151 | if (IS_RED (q) && IS_RED (p)) { 152 | /* Hard red violation: rotate */ 153 | if (!parent) { 154 | return false; 155 | } 156 | int dir2 = parent->link[1] == g; 157 | if (q == p->link[last]) { 158 | _set_link (parent, _rot_once (g, !last), dir2); 159 | } else { 160 | _set_link (parent, _rot_twice (g, !last), dir2); 161 | } 162 | } 163 | 164 | if (inserted) { 165 | break; 166 | } 167 | 168 | last = dir; 169 | dir = cmp (data, q->data, user) >= 0; 170 | 171 | if (g != NULL) { 172 | parent = g; 173 | } 174 | 175 | g = p; 176 | p = q; 177 | q = q->link[dir]; 178 | } 179 | 180 | /* Update root(it may different due to root rotation) */ 181 | tree->root = head.link[1]; 182 | 183 | out_exit: 184 | /* Invariant: root is black */ 185 | tree->root->red = 0; 186 | tree->root->parent = NULL; 187 | if (inserted) { 188 | tree->size++; 189 | } 190 | 191 | return inserted; 192 | } 193 | 194 | R_API bool r_rbtree_delete(RRBTree *tree, void *data, RRBComparator cmp, void *user) { 195 | r_return_val_if_fail (tree && data && tree->size && tree->root && cmp, false); 196 | 197 | RRBNode head = { .red = 0 }; 198 | RRBNode *q = &head, *p = NULL, *g = NULL; 199 | RRBNode *found = NULL; 200 | int dir = 1, last; 201 | 202 | _set_link (q, tree->root, 1); 203 | 204 | /* Find in-order predecessor */ 205 | while (q->link[dir] != NULL) { 206 | last = dir; 207 | 208 | g = p; 209 | p = q; 210 | q = q->link[dir]; 211 | 212 | dir = cmp (data, q->data, user); 213 | if (dir == 0) { 214 | found = q; 215 | } 216 | 217 | dir = dir > 0; 218 | 219 | if (!IS_RED (q) && !IS_RED (q->link[dir])) { 220 | if (IS_RED (q->link[!dir])) { 221 | _set_link (p, _rot_once (q, dir), last); 222 | p = p->link[last]; 223 | } else { 224 | RRBNode *s = p->link[!last]; 225 | 226 | if (s != NULL) { 227 | if (!IS_RED (s->link[!last]) && !IS_RED (s->link[last])) { 228 | /* Color flip */ 229 | p->red = 0; 230 | s->red = 1; 231 | q->red = 1; 232 | } else { 233 | int dir2 = g->link[1] == p; 234 | 235 | if (IS_RED (s->link[last])) { 236 | _set_link (g, _rot_twice (p, last), dir2); 237 | } else { 238 | _set_link (g, _rot_once (p, last), dir2); 239 | } 240 | 241 | /* Ensure correct coloring */ 242 | q->red = g->link[dir2]->red = 1; 243 | g->link[dir2]->link[0]->red = 0; 244 | g->link[dir2]->link[1]->red = 0; 245 | } 246 | } 247 | } 248 | } 249 | } 250 | 251 | /* Replace and remove if found */ 252 | if (found) { 253 | found->data = q->data; 254 | _set_link (p, q->link[q->link[0] == NULL], p->link[1] == q); 255 | tree->free (q->data); 256 | free (q); 257 | tree->size--; 258 | } 259 | 260 | /* Update root node */ 261 | tree->root = head.link[1]; 262 | if (tree->root) { 263 | tree->root->red = 0; 264 | } else { 265 | r_return_val_if_fail (tree->size == 0, false); 266 | } 267 | return !!found; 268 | } 269 | 270 | R_API RRBNode *r_rbtree_first_node(RRBTree *tree) { 271 | r_return_val_if_fail (tree, NULL); 272 | if (!tree->root) { 273 | // empty tree 274 | return NULL; 275 | } 276 | RRBNode *node = tree->root; 277 | while (node->link[0]) { 278 | node = node->link[0]; 279 | } 280 | return node; 281 | } 282 | 283 | R_API RRBNode *r_rbtree_last_node(RRBTree *tree) { 284 | r_return_val_if_fail (tree, NULL); 285 | if (!tree->root) { 286 | // empty tree 287 | return NULL; 288 | } 289 | RRBNode *node = tree->root; 290 | while (node->link[1]) { 291 | node = node->link[1]; 292 | } 293 | return node; 294 | } 295 | 296 | R_API RRBNode *r_rbnode_next(RRBNode *node) { 297 | r_return_val_if_fail (node, NULL); 298 | if (node->link[1]) { 299 | node = node->link[1]; 300 | while (node->link[0]) { 301 | node = node->link[0]; 302 | } 303 | return node; 304 | } 305 | RRBNode *parent = node->parent; 306 | while (parent->link[1] == node) { 307 | node = parent; 308 | parent = node->parent; 309 | if (!parent) { 310 | return NULL; 311 | } 312 | } 313 | return parent; 314 | } 315 | 316 | R_API RRBNode *r_rbnode_prev(RRBNode *node) { 317 | r_return_val_if_fail (node, NULL); 318 | if (node->link[0]) { 319 | node = node->link[0]; 320 | while (node->link[1]) { 321 | node = node->link[1]; 322 | } 323 | return node; 324 | } 325 | RRBNode *parent = node->parent; 326 | while (parent->link[0] == node) { 327 | node = parent; 328 | parent = node->parent; 329 | if (!parent) { 330 | return NULL; 331 | } 332 | } 333 | return parent; 334 | } 335 | --------------------------------------------------------------------------------