GRASS 8 Programmer's Manual 8.6.0dev(2026)-8843f13794
Loading...
Searching...
No Matches
rbtree.c
Go to the documentation of this file.
1/*!
2 * \file rbtree.c
3 *
4 * \brief binary search tree
5 *
6 * Generic balanced binary search tree (Red Black Tree) implementation
7 *
8 * SPDX-FileCopyrightText: 2009 GRASS Development Team
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 *
11 * \author Original author Julienne Walker 2003, 2008
12 * GRASS implementation Markus Metz, 2009
13 */
14
15/* balanced binary search tree implementation
16 *
17 * this one is a Red Black Tree, no parent pointers, no threads
18 * The core code comes from Julienne Walker's tutorials on binary search trees
19 * original license: public domain
20 * http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
21 * some ideas come from libavl (GPL >= 2)
22 *
23 * Red Black Trees are used to maintain a data structure with
24 * search, insertion and deletion in O(log N) time
25 */
26
27#include <assert.h>
28#include <stdlib.h>
29#include <string.h>
30#include <grass/gis.h>
31#include <grass/glocale.h>
32#include <grass/rbtree.h>
33
34/* internal functions */
35static struct RB_NODE *rbtree_single(struct RB_NODE *, int);
36static struct RB_NODE *rbtree_double(struct RB_NODE *, int);
37static void *rbtree_first(struct RB_TRAV *);
38static void *rbtree_last(struct RB_TRAV *trav);
39static void *rbtree_next(struct RB_TRAV *);
40static void *rbtree_previous(struct RB_TRAV *);
41static struct RB_NODE *rbtree_make_node(size_t, void *);
42static int is_red(struct RB_NODE *);
43
44/* create new tree and initialize
45 * returns pointer to new tree, NULL for memory allocation error
46 */
48{
49 struct RB_TREE *tree = (struct RB_TREE *)malloc(sizeof(struct RB_TREE));
50
51 if (tree == NULL) {
52 G_warning("RB tree: Out of memory!");
53 return NULL;
54 }
55
57
58 tree->datasize = rb_datasize;
59 tree->rb_compare = compare;
60 tree->count = 0;
61 tree->root = NULL;
62
63 return tree;
64}
65
66/* add an item to a tree
67 * non-recursive top-down insertion
68 * the algorithm does not allow duplicates and also does not warn about a
69 * duplicate returns 1 on success, 0 on failure
70 */
71int rbtree_insert(struct RB_TREE *tree, void *data)
72{
73 assert(tree && data);
74
75 if (tree->root == NULL) {
76 /* create a new root node for tree */
77 tree->root = rbtree_make_node(tree->datasize, data);
78 if (tree->root == NULL)
79 return 0;
80 }
81 else {
82 struct RB_NODE head = {0, 0, {0, 0}}; /* False tree root */
83 struct RB_NODE *g, *t; /* Grandparent & parent */
84 struct RB_NODE *p, *q; /* Iterator & parent */
85 int dir = 0, last = 0;
86
87 /* Set up helpers */
88 t = &head;
89 g = p = NULL;
90 q = t->link[1] = tree->root;
91
92 /* Search down the tree */
93 for (;;) {
94 if (q == NULL) {
95 /* Insert new node at the bottom */
96 p->link[dir] = q = rbtree_make_node(tree->datasize, data);
97 if (q == NULL)
98 return 0;
99 }
100 else if (is_red(q->link[0]) && is_red(q->link[1])) {
101 /* Color flip */
102 q->red = 1;
103 q->link[0]->red = 0;
104 q->link[1]->red = 0;
105 }
106
107 /* Fix red violation */
108 if (is_red(q) && is_red(p)) {
109 int dir2 = t->link[1] == g;
110
111 if (q == p->link[last])
112 t->link[dir2] = rbtree_single(g, !last);
113 else
114 t->link[dir2] = rbtree_double(g, !last);
115 }
116
117 last = dir;
118 dir = tree->rb_compare(q->data, data);
119
120 /* Stop if found. This check also disallows duplicates in the tree
121 */
122 if (dir == 0)
123 break;
124
125 dir = dir < 0;
126
127 /* Move the helpers down */
128 if (g != NULL)
129 t = g;
130
131 g = p, p = q;
132 q = q->link[dir];
133 }
134
135 /* Update root */
136 tree->root = head.link[1];
137 }
138
139 /* Make root black */
140 tree->root->red = 0;
141
142 tree->count++;
143
144 return 1;
145}
146
147/* remove an item from a tree that matches given data
148 * non-recursive top-down removal
149 * returns 1 on successful removal
150 * returns 0 if data item was not found
151 */
152int rbtree_remove(struct RB_TREE *tree, const void *data)
153{
154 struct RB_NODE head = {0, 0, {0, 0}}; /* False tree root */
155 struct RB_NODE *q, *p, *g; /* Helpers */
156 struct RB_NODE *f = NULL; /* Found item */
157 int dir = 1, removed = 0;
158
159 assert(tree && data);
160
161 if (tree->root == NULL) {
162 return 0; /* empty tree, nothing to remove */
163 }
164
165 /* Set up helpers */
166 q = &head;
167 g = p = NULL;
168 q->link[1] = tree->root;
169
170 /* Search and push a red down */
171 while (q->link[dir] != NULL) {
172 int last = dir;
173
174 /* Update helpers */
175 g = p, p = q;
176 q = q->link[dir];
177 dir = tree->rb_compare(q->data, data);
178
179 /* Save found node */
180 if (dir == 0)
181 f = q;
182
183 dir = dir < 0;
184
185 /* Push the red node down */
186 if (!is_red(q) && !is_red(q->link[dir])) {
187 if (is_red(q->link[!dir]))
188 p = p->link[last] = rbtree_single(q, dir);
189 else if (!is_red(q->link[!dir])) {
190 struct RB_NODE *s = p->link[!last];
191
192 if (s != NULL) {
193 if (!is_red(s->link[!last]) && !is_red(s->link[last])) {
194 /* Color flip */
195 p->red = 0;
196 s->red = 1;
197 q->red = 1;
198 }
199 else {
200 int dir2 = g->link[1] == p;
201
202 if (is_red(s->link[last]))
203 g->link[dir2] = rbtree_double(p, last);
204 else if (is_red(s->link[!last]))
205 g->link[dir2] = rbtree_single(p, last);
206
207 /* Ensure correct coloring */
208 q->red = g->link[dir2]->red = 1;
209 g->link[dir2]->link[0]->red = 0;
210 g->link[dir2]->link[1]->red = 0;
211 }
212 }
213 }
214 }
215 }
216
217 /* Replace and remove if found */
218 if (f != NULL) {
219 free(f->data);
220 f->data = q->data;
221 p->link[p->link[1] == q] = q->link[q->link[0] == NULL];
222 free(q);
223 q = NULL;
224 tree->count--;
225 removed = 1;
226 }
227 else
228 G_debug(2, "RB tree: data not found in search tree");
229
230 /* Update root and make it black */
231 tree->root = head.link[1];
232 if (tree->root != NULL)
233 tree->root->red = 0;
234
235 return removed;
236}
237
238/* find data item in tree
239 * returns pointer to data item if found else NULL
240 */
241void *rbtree_find(struct RB_TREE *tree, const void *data)
242{
243 struct RB_NODE *curr_node = tree->root;
244 int cmp;
245
246 assert(tree && data);
247
248 while (curr_node != NULL) {
249 cmp = tree->rb_compare(curr_node->data, data);
250 if (cmp == 0)
251 return curr_node->data; /* found */
252
253 curr_node = curr_node->link[cmp < 0];
254 }
255 return NULL;
256}
257
258/* initialize tree traversal
259 * (re-)sets trav structure
260 * returns 0
261 */
262int rbtree_init_trav(struct RB_TRAV *trav, struct RB_TREE *tree)
263{
264 assert(trav && tree);
265
266 trav->tree = tree;
267 trav->curr_node = tree->root;
268 trav->first = 1;
269 trav->top = 0;
270
271 return 0;
272}
273
274/* traverse the tree in ascending order
275 * useful to get all items in the tree non-recursively
276 * struct RB_TRAV *trav needs to be initialized first
277 * returns pointer to data, NULL when finished
278 */
280{
281 assert(trav);
282
283 if (trav->curr_node == NULL) {
284 if (trav->first)
285 G_debug(1, "RB tree: empty tree");
286 else
287 G_debug(1, "RB tree: finished traversing");
288
289 return NULL;
290 }
291
292 if (!trav->first)
293 return rbtree_next(trav);
294 else {
295 trav->first = 0;
296 return rbtree_first(trav);
297 }
298}
299
300/* traverse the tree in descending order
301 * useful to get all items in the tree non-recursively
302 * struct RB_TRAV *trav needs to be initialized first
303 * returns pointer to data, NULL when finished
304 */
306{
307 assert(trav);
308
309 if (trav->curr_node == NULL) {
310 if (trav->first)
311 G_debug(1, "RB tree: empty tree");
312 else
313 G_debug(1, "RB tree: finished traversing");
314
315 return NULL;
316 }
317
318 if (!trav->first)
319 return rbtree_previous(trav);
320 else {
321 trav->first = 0;
322 return rbtree_last(trav);
323 }
324}
325
326/* find start point to traverse the tree in ascending order
327 * useful to get a selection of items in the tree
328 * magnitudes faster than traversing the whole tree
329 * may return first item that's smaller or first item that's larger
330 * struct RB_TRAV *trav needs to be initialized first
331 * returns pointer to data, NULL when finished
332 */
333void *rbtree_traverse_start(struct RB_TRAV *trav, const void *data)
334{
335 int dir = 0;
336
337 assert(trav && data);
338
339 if (trav->curr_node == NULL) {
340 if (trav->first)
341 G_warning("RB tree: empty tree");
342 else
343 G_warning("RB tree: finished traversing");
344
345 return NULL;
346 }
347
348 if (!trav->first)
349 return rbtree_next(trav);
350
351 /* else first time, get start node */
352
353 trav->first = 0;
354 trav->top = 0;
355
356 while (trav->curr_node != NULL) {
357 dir = trav->tree->rb_compare(trav->curr_node->data, data);
358 /* exact match, great! */
359 if (dir == 0)
360 return trav->curr_node->data;
361 else {
362 dir = dir < 0;
363 /* end of branch, also reached if
364 * smallest item is larger than search template or
365 * largest item is smaller than search template */
366 if (trav->curr_node->link[dir] == NULL)
367 return trav->curr_node->data;
368
369 trav->up[trav->top++] = trav->curr_node;
370 trav->curr_node = trav->curr_node->link[dir];
371 }
372 }
373
374 return NULL; /* should not happen */
375}
376
377/* two functions needed to fully traverse the tree: initialize and continue
378 * useful to get all items in the tree non-recursively
379 * this one here uses a stack
380 * parent pointers or threads would also be possible
381 * but these would need to be added to RB_NODE
382 * -> more memory needed for standard operations
383 */
384
385/* start traversing the tree
386 * returns pointer to smallest data item
387 */
388static void *rbtree_first(struct RB_TRAV *trav)
389{
390 /* get smallest item */
391 while (trav->curr_node->link[0] != NULL) {
392 trav->up[trav->top++] = trav->curr_node;
393 trav->curr_node = trav->curr_node->link[0];
394 }
395
396 return trav->curr_node->data; /* return smallest item */
397}
398
399/* start traversing the tree
400 * returns pointer to largest data item
401 */
402static void *rbtree_last(struct RB_TRAV *trav)
403{
404 /* get smallest item */
405 while (trav->curr_node->link[1] != NULL) {
406 trav->up[trav->top++] = trav->curr_node;
407 trav->curr_node = trav->curr_node->link[1];
408 }
409
410 return trav->curr_node->data; /* return smallest item */
411}
412
413/* continue traversing the tree in ascending order
414 * returns pointer to data item, NULL when finished
415 */
416void *rbtree_next(struct RB_TRAV *trav)
417{
418 if (trav->curr_node->link[1] != NULL) {
419 /* something on the right side: larger item */
420 trav->up[trav->top++] = trav->curr_node;
421 trav->curr_node = trav->curr_node->link[1];
422
423 /* go down, find smallest item in this branch */
424 while (trav->curr_node->link[0] != NULL) {
425 trav->up[trav->top++] = trav->curr_node;
426 trav->curr_node = trav->curr_node->link[0];
427 }
428 }
429 else {
430 /* at smallest item in this branch, go back up */
431 struct RB_NODE *last;
432
433 do {
434 if (trav->top == 0) {
435 trav->curr_node = NULL;
436 break;
437 }
438 last = trav->curr_node;
439 trav->curr_node = trav->up[--trav->top];
440 } while (last == trav->curr_node->link[1]);
441 }
442
443 if (trav->curr_node != NULL) {
444 return trav->curr_node->data;
445 }
446 else
447 return NULL; /* finished traversing */
448}
449
450/* continue traversing the tree in descending order
451 * returns pointer to data item, NULL when finished
452 */
453void *rbtree_previous(struct RB_TRAV *trav)
454{
455 if (trav->curr_node->link[0] != NULL) {
456 /* something on the left side: smaller item */
457 trav->up[trav->top++] = trav->curr_node;
458 trav->curr_node = trav->curr_node->link[0];
459
460 /* go down, find largest item in this branch */
461 while (trav->curr_node->link[1] != NULL) {
462 trav->up[trav->top++] = trav->curr_node;
463 trav->curr_node = trav->curr_node->link[1];
464 }
465 }
466 else {
467 /* at largest item in this branch, go back up */
468 struct RB_NODE *last;
469
470 do {
471 if (trav->top == 0) {
472 trav->curr_node = NULL;
473 break;
474 }
475 last = trav->curr_node;
476 trav->curr_node = trav->up[--trav->top];
477 } while (last == trav->curr_node->link[0]);
478 }
479
480 if (trav->curr_node != NULL) {
481 return trav->curr_node->data;
482 }
483 else
484 return NULL; /* finished traversing */
485}
486
487/* clear the tree, removing all entries */
488void rbtree_clear(struct RB_TREE *tree)
489{
490 struct RB_NODE *it;
491 struct RB_NODE *save = tree->root;
492
493 /*
494 Rotate away the left links so that
495 we can treat this like the destruction
496 of a linked list
497 */
498 while ((it = save) != NULL) {
499 if (it->link[0] == NULL) {
500 /* No left links, just kill the node and move on */
501 save = it->link[1];
502 free(it->data);
503 it->data = NULL;
504 free(it);
505 it = NULL;
506 }
507 else {
508 /* Rotate away the left link and check again */
509 save = it->link[0];
510 it->link[0] = save->link[1];
511 save->link[1] = it;
512 }
513 }
514 tree->root = NULL;
515}
516
517/* destroy the tree */
518void rbtree_destroy(struct RB_TREE *tree)
519{
520 /* remove all entries */
521 rbtree_clear(tree);
522
523 free(tree);
524 tree = NULL;
525}
526
527/* used for debugging: check for errors in tree structure */
528int rbtree_debug(struct RB_TREE *tree, struct RB_NODE *root)
529{
530 int lh, rh;
531
532 if (root == NULL)
533 return 1;
534 else {
535 struct RB_NODE *ln = root->link[0];
536 struct RB_NODE *rn = root->link[1];
537 int lcmp = 0, rcmp = 0;
538
539 /* Consecutive red links */
540 if (is_red(root)) {
541 if (is_red(ln) || is_red(rn)) {
542 G_warning("Red Black Tree debugging: Red violation");
543 return 0;
544 }
545 }
546
547 lh = rbtree_debug(tree, ln);
548 rh = rbtree_debug(tree, rn);
549
550 if (ln) {
551 lcmp = tree->rb_compare(ln->data, root->data);
552 }
553
554 if (rn) {
555 rcmp = tree->rb_compare(rn->data, root->data);
556 }
557
558 /* Invalid binary search tree:
559 * left node >= parent or right node <= parent */
560 if ((ln != NULL && lcmp > -1) || (rn != NULL && rcmp < 1)) {
561 G_warning("Red Black Tree debugging: Binary tree violation");
562 return 0;
563 }
564
565 /* Black height mismatch */
566 if (lh != 0 && rh != 0 && lh != rh) {
567 G_warning("Red Black Tree debugging: Black violation");
568 return 0;
569 }
570
571 /* Only count black links */
572 if (lh != 0 && rh != 0)
573 return is_red(root) ? lh : lh + 1;
574 else
575 return 0;
576 }
577}
578
579/*******************************************************
580 * *
581 * internal functions for Red Black Tree maintenance *
582 * *
583 *******************************************************/
584
585/* add a new node to the tree */
586static struct RB_NODE *rbtree_make_node(size_t datasize, void *data)
587{
588 struct RB_NODE *new_node = (struct RB_NODE *)malloc(sizeof(*new_node));
589
590 if (new_node == NULL)
591 G_fatal_error("RB Search Tree: Out of memory!");
592
593 new_node->data = malloc(datasize);
594 if (new_node->data == NULL)
595 G_fatal_error("RB Search Tree: Out of memory!");
596
597 memcpy(new_node->data, data, datasize);
598 new_node->red = 1; /* 1 is red, 0 is black */
599 new_node->link[0] = NULL;
600 new_node->link[1] = NULL;
601
602 return new_node;
603}
604
605/* check for red violation */
606static int is_red(struct RB_NODE *root)
607{
608 if (root)
609 return root->red == 1;
610
611 return 0;
612}
613
614/* single rotation */
615static struct RB_NODE *rbtree_single(struct RB_NODE *root, int dir)
616{
617 struct RB_NODE *newroot = root->link[!dir];
618
619 root->link[!dir] = newroot->link[dir];
620 newroot->link[dir] = root;
621
622 root->red = 1;
623 newroot->red = 0;
624
625 return newroot;
626}
627
628/* double rotation */
629static struct RB_NODE *rbtree_double(struct RB_NODE *root, int dir)
630{
631 root->link[!dir] = rbtree_single(root->link[!dir], !dir);
632 return rbtree_single(root, dir);
633}
#define NULL
Definition ccmath.h:32
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int compare(const void *a, const void *b)
Definition dgraph.c:166
#define assert(condition)
Definition lz4.c:291
float g
Definition named_colr.c:7
double t
Definition r_raster.c:37
void * rbtree_find(struct RB_TREE *tree, const void *data)
Definition rbtree.c:241
void rbtree_destroy(struct RB_TREE *tree)
Definition rbtree.c:518
int rbtree_remove(struct RB_TREE *tree, const void *data)
Definition rbtree.c:152
int rbtree_debug(struct RB_TREE *tree, struct RB_NODE *root)
Definition rbtree.c:528
void * rbtree_traverse(struct RB_TRAV *trav)
Definition rbtree.c:279
int rbtree_init_trav(struct RB_TRAV *trav, struct RB_TREE *tree)
Definition rbtree.c:262
void * rbtree_traverse_start(struct RB_TRAV *trav, const void *data)
Definition rbtree.c:333
void rbtree_clear(struct RB_TREE *tree)
Definition rbtree.c:488
void * rbtree_traverse_backwd(struct RB_TRAV *trav)
Definition rbtree.c:305
struct RB_TREE * rbtree_create(rb_compare_fn *compare, size_t rb_datasize)
Definition rbtree.c:47
int rbtree_insert(struct RB_TREE *tree, void *data)
Definition rbtree.c:71
int rb_compare_fn(const void *rb_a, const void *rb_b)
Definition rbtree.h:76
void * malloc(unsigned)
void free(void *)
void * data
Definition rbtree.h:80
struct RB_NODE * link[2]
Definition rbtree.h:81
unsigned char red
Definition rbtree.h:79
size_t datasize
Definition rbtree.h:87
struct RB_NODE * root
Definition rbtree.h:86
size_t count
Definition rbtree.h:88
rb_compare_fn * rb_compare
Definition rbtree.h:89