4
* \brief binary search tree
6
* Generic balanced binary search tree (Red Black Tree) implementation
8
* (C) 2009 by the GRASS Development Team
10
* This program is free software under the GNU General Public License
11
* (>=v2). Read the file COPYING that comes with GRASS for details.
13
* \author Original author Julienne Walker 2003, 2008
14
* GRASS implementation Markus Metz, 2009
17
/* balanced binary search tree implementation
19
* this one is a Red Black Tree, no parent pointers, no threads
20
* The core code comes from Julienne Walker's tutorials on binary search trees
21
* original license: public domain
22
* http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
23
* some ideas come from libavl (GPL >= 2)
25
* Red Black Trees are used to maintain a data structure with
26
* search, insertion and deletion in O(log N) time
32
#include <grass/gis.h>
33
#include <grass/glocale.h>
36
/* internal functions */
37
static struct RG_NODE *rgtree_single(struct RG_NODE *, int);
38
static struct RG_NODE *rgtree_double(struct RG_NODE *, int);
39
static struct reg_stats *rgtree_first(struct RG_TRAV *);
40
static struct reg_stats *rgtree_next(struct RG_TRAV *);
41
static struct RG_NODE *rgtree_make_node(size_t, struct reg_stats *);
42
static int is_red(struct RG_NODE *);
45
int compare_regstat(struct reg_stats *a, struct reg_stats *b)
47
return (a->id - b->id);
51
/* create new tree and initialize
52
* returns pointer to new tree, NULL for memory allocation error
54
struct RG_TREE *rgtree_create(int nbands, size_t rb_datasize)
56
struct RG_TREE *tree = (struct RG_TREE *)malloc(sizeof(struct RG_TREE));
59
G_warning("RB tree: Out of memory!");
63
tree->datasize = rb_datasize;
64
tree->cmp = compare_regstat;
66
tree->nbands = nbands;
72
/* add an item to a tree
73
* non-recursive top-down insertion
74
* the algorithm does not allow duplicates and also does not warn about a duplicate
75
* returns 1 on success, 0 on failure
77
int rgtree_insert(struct RG_TREE *tree, struct reg_stats *data)
81
if (tree->root == NULL) {
82
/* create a new root node for tree */
83
tree->root = rgtree_make_node(tree->datasize, data);
84
if (tree->root == NULL)
88
struct RG_NODE head = { 0, {0, 0}, {0, 0, 0, 0} }; /* False tree root */
89
struct RG_NODE *g, *t; /* Grandparent & parent */
90
struct RG_NODE *p, *q; /* Iterator & parent */
91
int dir = 0, last = 0;
96
q = t->link[1] = tree->root;
98
/* Search down the tree */
101
/* Insert new node at the bottom */
102
p->link[dir] = q = rgtree_make_node(tree->datasize, data);
106
else if (is_red(q->link[0]) && is_red(q->link[1])) {
113
/* Fix red violation */
114
if (is_red(q) && is_red(p)) {
115
int dir2 = t->link[1] == g;
117
if (q == p->link[last])
118
t->link[dir2] = rgtree_single(g, !last);
120
t->link[dir2] = rgtree_double(g, !last);
124
dir = tree->cmp(&(q->data), data);
126
/* Stop if found. This check also disallows duplicates in the tree */
132
/* Move the helpers down */
141
tree->root = head.link[1];
144
/* Make root black */
152
/* remove an item from a tree that matches given data
153
* non-recursive top-down removal
154
* returns 1 on successful removal
155
* returns 0 if data item was not found
157
int rgtree_remove(struct RG_TREE *tree, struct reg_stats *data)
159
struct RG_NODE head = { 0, {0, 0}, {0, 0, 0, 0} }; /* False tree root */
160
struct RG_NODE *q, *p, *g; /* Helpers */
161
struct RG_NODE *f = NULL; /* Found item */
162
int dir = 1, removed = 0;
164
assert(tree && data);
166
if (tree->root == NULL) {
167
return 0; /* empty tree, nothing to remove */
173
q->link[1] = tree->root;
175
/* Search and push a red down */
176
while (q->link[dir] != NULL) {
182
dir = tree->cmp(&(q->data), data);
184
/* Save found node */
190
/* Push the red node down */
191
if (!is_red(q) && !is_red(q->link[dir])) {
192
if (is_red(q->link[!dir]))
193
p = p->link[last] = rgtree_single(q, dir);
194
else if (!is_red(q->link[!dir])) {
195
struct RG_NODE *s = p->link[!last];
198
if (!is_red(s->link[!last]) && !is_red(s->link[last])) {
205
int dir2 = g->link[1] == p;
207
if (is_red(s->link[last]))
208
g->link[dir2] = rgtree_double(p, last);
209
else if (is_red(s->link[!last]))
210
g->link[dir2] = rgtree_single(p, last);
212
/* Ensure correct coloring */
213
q->red = g->link[dir2]->red = 1;
214
g->link[dir2]->link[0]->red = 0;
215
g->link[dir2]->link[1]->red = 0;
222
/* Replace and remove if found */
225
f->data.id = q->data.id;
226
f->data.count = q->data.count;
227
memcpy(f->data.sum, q->data.sum, tree->datasize);
228
memcpy(f->data.mean, q->data.mean, tree->datasize);
230
memcpy(f->data.min, q->data.min, tree->datasize);
231
memcpy(f->data.max, q->data.max, tree->datasize);
234
p->link[p->link[1] == q] = q->link[q->link[0] == NULL];
248
G_debug(2, "RB tree: data not found in search tree");
250
/* Update root and make it black */
251
tree->root = head.link[1];
252
if (tree->root != NULL)
258
/* find data item in tree
259
* returns pointer to data item if found else NULL
261
struct reg_stats *rgtree_find(struct RG_TREE *tree, struct reg_stats *data)
263
struct RG_NODE *curr_node = tree->root;
266
assert(tree && data);
268
while (curr_node != NULL) {
269
cmp = tree->cmp(&(curr_node->data), data);
271
return &curr_node->data; /* found */
273
curr_node = curr_node->link[cmp < 0];
278
/* initialize tree traversal
279
* (re-)sets trav structure
282
int rgtree_init_trav(struct RG_TRAV *trav, struct RG_TREE *tree)
284
assert(trav && tree);
287
trav->curr_node = tree->root;
294
/* traverse the tree in ascending order
295
* useful to get all items in the tree non-recursively
296
* struct RG_TRAV *trav needs to be initialized first
297
* returns pointer to data, NULL when finished
299
struct reg_stats *rgtree_traverse(struct RG_TRAV *trav)
303
if (trav->curr_node == NULL) {
305
G_debug(1, "RB tree: empty tree");
307
G_debug(1, "RB tree: finished traversing");
313
return rgtree_next(trav);
316
return rgtree_first(trav);
320
/* find start point to traverse the tree in ascending order
321
* useful to get a selection of items in the tree
322
* magnitudes faster than traversing the whole tree
323
* may return first item that's smaller or first item that's larger
324
* struct RG_TRAV *trav needs to be initialized first
325
* returns pointer to data, NULL when finished
327
struct reg_stats *rgtree_traverse_start(struct RG_TRAV *trav, struct reg_stats *data)
331
assert(trav && data);
333
if (trav->curr_node == NULL) {
335
G_warning("RB tree: empty tree");
337
G_warning("RB tree: finished traversing");
343
return rgtree_next(trav);
345
/* else first time, get start node */
350
while (trav->curr_node != NULL) {
351
dir = trav->tree->cmp(&(trav->curr_node->data), data);
352
/* exact match, great! */
354
return &(trav->curr_node->data);
357
/* end of branch, also reached if
358
* smallest item is larger than search template or
359
* largest item is smaller than search template */
360
if (trav->curr_node->link[dir] == NULL)
361
return &(trav->curr_node->data);
363
trav->up[trav->top++] = trav->curr_node;
364
trav->curr_node = trav->curr_node->link[dir];
368
return NULL; /* should not happen */
371
/* two functions needed to fully traverse the tree: initialize and continue
372
* useful to get all items in the tree non-recursively
373
* this one here uses a stack
374
* parent pointers or threads would also be possible
375
* but these would need to be added to RG_NODE
376
* -> more memory needed for standard operations
379
/* start traversing the tree
380
* returns pointer to smallest data item
382
static struct reg_stats *rgtree_first(struct RG_TRAV *trav)
384
/* get smallest item */
385
while (trav->curr_node->link[0] != NULL) {
386
trav->up[trav->top++] = trav->curr_node;
387
trav->curr_node = trav->curr_node->link[0];
390
return &(trav->curr_node->data); /* return smallest item */
393
/* continue traversing the tree in ascending order
394
* returns pointer to data item, NULL when finished
396
static struct reg_stats *rgtree_next(struct RG_TRAV *trav)
398
if (trav->curr_node->link[1] != NULL) {
399
/* something on the right side: larger item */
400
trav->up[trav->top++] = trav->curr_node;
401
trav->curr_node = trav->curr_node->link[1];
403
/* go down, find smallest item in this branch */
404
while (trav->curr_node->link[0] != NULL) {
405
trav->up[trav->top++] = trav->curr_node;
406
trav->curr_node = trav->curr_node->link[0];
410
/* at smallest item in this branch, go back up */
411
struct RG_NODE *last;
414
if (trav->top == 0) {
415
trav->curr_node = NULL;
418
last = trav->curr_node;
419
trav->curr_node = trav->up[--trav->top];
420
} while (last == trav->curr_node->link[1]);
423
if (trav->curr_node != NULL) {
424
return &(trav->curr_node->data);
427
return NULL; /* finished traversing */
430
/* destroy the tree */
431
void rgtree_destroy(struct RG_TREE *tree)
434
struct RG_NODE *save = tree->root;
437
Rotate away the left links so that
438
we can treat this like the destruction
441
while((it = save) != NULL) {
442
if (it->link[0] == NULL) {
443
/* No left links, just kill the node and move on */
451
/* Rotate away the left link and check again */
453
it->link[0] = save->link[1];
463
/* used for debugging: check for errors in tree structure */
464
int rgtree_debug(struct RG_TREE *tree, struct RG_NODE *root)
471
struct RG_NODE *ln = root->link[0];
472
struct RG_NODE *rn = root->link[1];
473
int lcmp = 0, rcmp = 0;
475
/* Consecutive red links */
477
if (is_red(ln) || is_red(rn)) {
478
G_warning("Red Black Tree debugging: Red violation");
483
lh = rgtree_debug(tree, ln);
484
rh = rgtree_debug(tree, rn);
487
lcmp = tree->cmp(&(ln->data), &(root->data));
491
rcmp = tree->cmp(&(rn->data), &(root->data));
494
/* Invalid binary search tree:
495
* left node >= parent or right node <= parent */
496
if ((ln != NULL && lcmp > -1)
497
|| (rn != NULL && rcmp < 1)) {
498
G_warning("Red Black Tree debugging: Binary tree violation");
502
/* Black height mismatch */
503
if (lh != 0 && rh != 0 && lh != rh) {
504
G_warning("Red Black Tree debugging: Black violation");
508
/* Only count black links */
509
if (lh != 0 && rh != 0)
510
return is_red(root) ? lh : lh + 1;
516
/*******************************************************
518
* internal functions for Red Black Tree maintenance *
520
*******************************************************/
522
/* add a new node to the tree */
523
static struct RG_NODE *rgtree_make_node(size_t datasize, struct reg_stats *data)
525
struct RG_NODE *new_node = (struct RG_NODE *)malloc(sizeof(*new_node));
527
if (new_node == NULL)
528
G_fatal_error("RB Search Tree: Out of memory!");
530
if ((new_node->data.sum = malloc(datasize)) == NULL)
531
G_fatal_error("RB Search Tree: Out of memory!");
532
if ((new_node->data.mean = malloc(datasize)) == NULL)
533
G_fatal_error("RB Search Tree: Out of memory!");
535
if ((new_node->data.min = malloc(datasize)) == NULL)
536
G_fatal_error("RB Search Tree: Out of memory!");
537
if ((new_node->data.max = malloc(datasize)) == NULL)
538
G_fatal_error("RB Search Tree: Out of memory!");
542
new_node->data.id = data->id;
543
new_node->data.count = data->count;
544
memcpy(new_node->data.sum, data->sum, datasize);
545
memcpy(new_node->data.mean, data->mean, datasize);
547
memcpy(new_node->data.min, data->min, datasize);
548
memcpy(new_node->data.max, data->max, datasize);
551
new_node->red = 1; /* 1 is red, 0 is black */
552
new_node->link[0] = NULL;
553
new_node->link[1] = NULL;
558
/* check for red violation */
559
static int is_red(struct RG_NODE *root)
562
return root->red == 1;
567
/* single rotation */
568
static struct RG_NODE *rgtree_single(struct RG_NODE *root, int dir)
570
struct RG_NODE *newroot = root->link[!dir];
572
root->link[!dir] = newroot->link[dir];
573
newroot->link[dir] = root;
581
/* double rotation */
582
static struct RG_NODE *rgtree_double(struct RG_NODE *root, int dir)
584
root->link[!dir] = rgtree_single(root->link[!dir], !dir);
585
return rgtree_single(root, dir);