2 * rbtree.c Red-black balanced binary trees.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2004,2006 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/autoconf.h>
31 #include <freeradius-devel/missing.h>
32 #include <freeradius-devel/libradius.h>
34 /* red-black tree description */
35 typedef enum { Black, Red } NodeColor;
38 rbnode_t *Left; /* left child */
39 rbnode_t *Right; /* right child */
40 rbnode_t *Parent; /* parent */
41 NodeColor Color; /* node color (black, red) */
42 void *Data; /* data stored in node */
45 #define NIL &Sentinel /* all leafs are sentinels */
46 static rbnode_t Sentinel = { NIL, NIL, NULL, Black, NULL};
54 int (*Compare)(const void *, const void *);
56 void (*freeNode)(void *);
58 #define RBTREE_MAGIC (0x5ad09c42)
61 * Walks the tree to delete all nodes.
62 * Does NOT re-balance it!
64 static void FreeWalker(rbtree_t *tree, rbnode_t *X)
66 if (X->Left != NIL) FreeWalker(tree, X->Left);
67 if (X->Right != NIL) FreeWalker(tree, X->Right);
69 if (tree->freeNode) tree->freeNode(X->Data);
73 void rbtree_free(rbtree_t *tree)
78 * Walk the tree, deleting the nodes...
80 if (tree->Root != NIL) FreeWalker(tree, tree->Root);
90 * Create a new red-black tree.
92 rbtree_t *rbtree_create(int (*Compare)(const void *, const void *),
93 void (*freeNode)(void *),
98 if (!Compare) return NULL;
100 tree = malloc(sizeof(*tree));
101 if (!tree) return NULL;
103 memset(tree, 0, sizeof(*tree));
105 tree->magic = RBTREE_MAGIC;
108 tree->Compare = Compare;
109 tree->replace_flag = replace_flag;
110 tree->freeNode = freeNode;
116 static void RotateLeft(rbtree_t *tree, rbnode_t *X)
118 /**************************
119 * rotate Node X to left *
120 **************************/
122 rbnode_t *Y = X->Right;
124 /* establish X->Right link */
126 if (Y->Left != NIL) Y->Left->Parent = X;
128 /* establish Y->Parent link */
129 if (Y != NIL) Y->Parent = X->Parent;
131 if (X == X->Parent->Left)
134 X->Parent->Right = Y;
141 if (X != NIL) X->Parent = Y;
144 static void RotateRight(rbtree_t *tree, rbnode_t *X)
146 /****************************
147 * rotate Node X to right *
148 ****************************/
150 rbnode_t *Y = X->Left;
152 /* establish X->Left link */
154 if (Y->Right != NIL) Y->Right->Parent = X;
156 /* establish Y->Parent link */
157 if (Y != NIL) Y->Parent = X->Parent;
159 if (X == X->Parent->Right)
160 X->Parent->Right = Y;
169 if (X != NIL) X->Parent = Y;
172 static void InsertFixup(rbtree_t *tree, rbnode_t *X)
174 /*************************************
175 * maintain red-black tree balance *
176 * after inserting node X *
177 *************************************/
179 /* check red-black properties */
180 while (X != tree->Root && X->Parent->Color == Red) {
181 /* we have a violation */
182 if (X->Parent == X->Parent->Parent->Left) {
183 rbnode_t *Y = X->Parent->Parent->Right;
184 if (Y->Color == Red) {
187 X->Parent->Color = Black;
189 X->Parent->Parent->Color = Red;
190 X = X->Parent->Parent;
194 if (X == X->Parent->Right) {
195 /* make X a left child */
200 /* recolor and rotate */
201 X->Parent->Color = Black;
202 X->Parent->Parent->Color = Red;
203 RotateRight(tree, X->Parent->Parent);
207 /* mirror image of above code */
208 rbnode_t *Y = X->Parent->Parent->Left;
209 if (Y->Color == Red) {
212 X->Parent->Color = Black;
214 X->Parent->Parent->Color = Red;
215 X = X->Parent->Parent;
219 if (X == X->Parent->Left) {
221 RotateRight(tree, X);
223 X->Parent->Color = Black;
224 X->Parent->Parent->Color = Red;
225 RotateLeft(tree, X->Parent->Parent);
230 tree->Root->Color = Black;
235 * Insert an element into the tree.
237 int rbtree_insert(rbtree_t *tree, void *Data)
239 rbnode_t *Current, *Parent, *X;
241 /***********************************************
242 * allocate node for Data and insert in tree *
243 ***********************************************/
245 /* find where node belongs */
246 Current = tree->Root;
248 while (Current != NIL) {
252 * See if two entries are identical.
254 result = tree->Compare(Data, Current->Data);
257 * Don't replace the entry.
259 if (tree->replace_flag == 0) {
264 * Do replace the entry.
266 if (tree->freeNode) tree->freeNode(Current->Data);
267 Current->Data = Data;
272 Current = (result < 0) ? Current->Left : Current->Right;
276 if ((X = malloc (sizeof(*X))) == NULL) {
277 exit(1); /* FIXME! */
286 /* insert node in tree */
288 if (tree->Compare(Data, Parent->Data) <= 0)
296 InsertFixup(tree, X);
298 tree->num_elements++;
303 static void DeleteFixup(rbtree_t *tree, rbnode_t *X, rbnode_t *Parent)
305 /*************************************
306 * maintain red-black tree balance *
307 * after deleting node X *
308 *************************************/
310 while (X != tree->Root && X->Color == Black) {
311 if (X == Parent->Left) {
312 rbnode_t *W = Parent->Right;
313 if (W->Color == Red) {
315 Parent->Color = Red; /* Parent != NIL? */
316 RotateLeft(tree, Parent);
319 if (W->Left->Color == Black && W->Right->Color == Black) {
320 if (W != NIL) W->Color = Red;
324 if (W->Right->Color == Black) {
325 if (W->Left != NIL) W->Left->Color = Black;
327 RotateRight(tree, W);
330 W->Color = Parent->Color;
331 if (Parent != NIL) Parent->Color = Black;
332 if (W->Right->Color != Black) {
333 W->Right->Color = Black;
335 RotateLeft(tree, Parent);
339 rbnode_t *W = Parent->Left;
340 if (W->Color == Red) {
342 Parent->Color = Red; /* Parent != NIL? */
343 RotateRight(tree, Parent);
346 if (W->Right->Color == Black && W->Left->Color == Black) {
347 if (W != NIL) W->Color = Red;
351 if (W->Left->Color == Black) {
352 if (W->Right != NIL) W->Right->Color = Black;
357 W->Color = Parent->Color;
358 if (Parent != NIL) Parent->Color = Black;
359 if (W->Left->Color != Black) {
360 W->Left->Color = Black;
362 RotateRight(tree, Parent);
371 * Delete an element from the tree.
373 void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
378 /*****************************
379 * delete node Z from tree *
380 *****************************/
382 if (!Z || Z == NIL) return;
384 if (Z->Left == NIL || Z->Right == NIL) {
385 /* Y has a NIL node as a child */
388 /* find tree successor with a NIL node as a child */
390 while (Y->Left != NIL) Y = Y->Left;
393 /* X is Y's only child */
397 X = Y->Right; /* may be NIL! */
399 /* remove Y from the parent chain */
401 if (X != NIL) X->Parent = Parent;
404 if (Y == Parent->Left)
413 * Move the child's data to here, and then
414 * re-balance the tree.
416 if (tree->freeNode) tree->freeNode(Z->Data);
419 } else if (tree->freeNode) {
420 tree->freeNode(Z->Data);
423 if (Y->Color == Black && X != NIL)
424 DeleteFixup(tree, X, Parent);
428 tree->num_elements--;
432 * Delete a node from the tree, based on given data, which MUST
433 * have come from rbtree_finddata().
435 int rbtree_deletebydata(rbtree_t *tree, const void *data)
437 rbnode_t *node = rbtree_find(tree, data);
439 if (!node) return 0; /* false */
441 rbtree_delete(tree, node);
448 * Find an element in the tree, returning the data, not the node.
450 rbnode_t *rbtree_find(rbtree_t *tree, const void *Data)
452 /*******************************
453 * find node containing Data *
454 *******************************/
456 rbnode_t *Current = tree->Root;
458 while (Current != NIL) {
459 int result = tree->Compare(Data, Current->Data);
464 Current = (result < 0) ?
465 Current->Left : Current->Right;
472 * Find the user data.
474 void *rbtree_finddata(rbtree_t *tree, const void *Data)
478 X = rbtree_find(tree, Data);
485 * Walk the tree, Pre-order
487 * We call ourselves recursively for each function, but that's OK,
488 * as the stack is only log(N) deep, which is ~12 entries deep.
490 static int WalkNodePreOrder(rbnode_t *X,
491 int (*callback)(void *, void *), void *context)
495 rcode = callback(context, X->Data);
496 if (rcode != 0) return rcode;
498 if (X->Left != NIL) {
499 rcode = WalkNodePreOrder(X->Left, callback, context);
500 if (rcode != 0) return rcode;
503 if (X->Right != NIL) {
504 rcode = WalkNodePreOrder(X->Right, callback, context);
505 if (rcode != 0) return rcode;
508 return 0; /* we know everything returned zero */
514 static int WalkNodeInOrder(rbnode_t *X,
515 int (*callback)(void *, void *), void *context)
519 if (X->Left != NIL) {
520 rcode = WalkNodeInOrder(X->Left, callback, context);
521 if (rcode != 0) return rcode;
524 rcode = callback(context, X->Data);
525 if (rcode != 0) return rcode;
527 if (X->Right != NIL) {
528 rcode = WalkNodeInOrder(X->Right, callback, context);
529 if (rcode != 0) return rcode;
532 return 0; /* we know everything returned zero */
539 static int WalkNodePostOrder(rbnode_t *X,
540 int (*callback)(void *, void*), void *context)
544 if (X->Left != NIL) {
545 rcode = WalkNodeInOrder(X->Left, callback, context);
546 if (rcode != 0) return rcode;
549 if (X->Right != NIL) {
550 rcode = WalkNodeInOrder(X->Right, callback, context);
551 if (rcode != 0) return rcode;
554 rcode = callback(context, X->Data);
555 if (rcode != 0) return rcode;
557 return 0; /* we know everything returned zero */
561 * Walk the entire tree. The callback function CANNOT modify
564 * The callback function should return 0 to continue walking.
565 * Any other value stops the walk, and is returned.
567 int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
568 int (*callback)(void *, void *), void *context)
572 return WalkNodePreOrder(tree->Root, callback, context);
574 return WalkNodeInOrder(tree->Root, callback, context);
576 return WalkNodePostOrder(tree->Root, callback, context);
585 int rbtree_num_elements(rbtree_t *tree)
589 return tree->num_elements;
594 * Given a Node, return the data.
596 void *rbtree_node2data(rbtree_t *tree, rbnode_t *node)
598 tree = tree; /* -Wunused */
600 if (!node) return NULL;