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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 * Copyright 2004 The FreeRADIUS server project
23 static const char rcsid[] = "$Id$";
31 * Some of these things should later go into a header file...
33 typedef struct rbtree_t rbtree_t;
34 typedef struct rbnode_t rbnode_t;
36 /* red-black tree description */
37 typedef enum { Black, Red } NodeColor;
39 /* callback order for walking */
40 typedef enum { PreOrder, InOrder, PostOrder } NodeCallback;
43 rbnode_t *Left; /* left child */
44 rbnode_t *Right; /* right child */
45 rbnode_t *Parent; /* parent */
46 NodeColor Color; /* node color (black, red) */
47 void *Data; /* data stored in node */
50 #define NIL &Sentinel /* all leafs are sentinels */
51 static rbnode_t Sentinel = { NIL, NIL, NULL, Black, NULL};
58 int (*Compare)(const void *, const void *);
60 void (*freeNode)(void *);
62 #define RBTREE_MAGIC (0x5ad09c42)
65 * Walks the tree to delete all nodes.
66 * Does NOT re-balance it!
68 static void FreeWalker(rbtree_t *tree, rbnode_t *X)
70 if (X->Left != NIL) FreeWalker(tree, X->Left);
71 if (X->Right != NIL) FreeWalker(tree, X->Right);
73 if (tree->freeNode) tree->freeNode(X->Data);
77 void rbtree_free(rbtree_t *tree)
82 * Walk the tree, deleting the nodes...
84 if (tree->Root != NULL) FreeWalker(tree, tree->Root);
94 * Create a new red-black tree.
96 rbtree_t *rbtree_create(int (*Compare)(const void *, const void *),
97 void (*freeNode)(void *),
102 if (!Compare) return NULL;
104 tree = malloc(sizeof(*tree));
105 if (!tree) return NULL;
107 memset(tree, 0, sizeof(*tree));
109 tree->magic = RBTREE_MAGIC;
112 tree->Compare = Compare;
113 tree->replace_flag = replace_flag;
114 tree->freeNode = freeNode;
120 static void RotateLeft(rbtree_t *tree, rbnode_t *X)
122 /**************************
123 * rotate Node X to left *
124 **************************/
126 rbnode_t *Y = X->Right;
128 /* establish X->Right link */
130 if (Y->Left != NIL) Y->Left->Parent = X;
132 /* establish Y->Parent link */
133 if (Y != NIL) Y->Parent = X->Parent;
135 if (X == X->Parent->Left)
138 X->Parent->Right = Y;
145 if (X != NIL) X->Parent = Y;
148 static void RotateRight(rbtree_t *tree, rbnode_t *X)
150 /****************************
151 * rotate Node X to right *
152 ****************************/
154 rbnode_t *Y = X->Left;
156 /* establish X->Left link */
158 if (Y->Right != NIL) Y->Right->Parent = X;
160 /* establish Y->Parent link */
161 if (Y != NIL) Y->Parent = X->Parent;
163 if (X == X->Parent->Right)
164 X->Parent->Right = Y;
173 if (X != NIL) X->Parent = Y;
176 static void InsertFixup(rbtree_t *tree, rbnode_t *X)
178 /*************************************
179 * maintain red-black tree balance *
180 * after inserting node X *
181 *************************************/
183 /* check red-black properties */
184 while (X != tree->Root && X->Parent->Color == Red) {
185 /* we have a violation */
186 if (X->Parent == X->Parent->Parent->Left) {
187 rbnode_t *Y = X->Parent->Parent->Right;
188 if (Y->Color == Red) {
191 X->Parent->Color = Black;
193 X->Parent->Parent->Color = Red;
194 X = X->Parent->Parent;
198 if (X == X->Parent->Right) {
199 /* make X a left child */
204 /* recolor and rotate */
205 X->Parent->Color = Black;
206 X->Parent->Parent->Color = Red;
207 RotateRight(tree, X->Parent->Parent);
211 /* mirror image of above code */
212 rbnode_t *Y = X->Parent->Parent->Left;
213 if (Y->Color == Red) {
216 X->Parent->Color = Black;
218 X->Parent->Parent->Color = Red;
219 X = X->Parent->Parent;
223 if (X == X->Parent->Left) {
225 RotateRight(tree, X);
227 X->Parent->Color = Black;
228 X->Parent->Parent->Color = Red;
229 RotateLeft(tree, X->Parent->Parent);
234 tree->Root->Color = Black;
239 * Insert an element into the tree.
241 int rbtree_insert(rbtree_t *tree, void *Data)
243 rbnode_t *Current, *Parent, *X;
245 /***********************************************
246 * allocate node for Data and insert in tree *
247 ***********************************************/
249 /* find where node belongs */
250 Current = tree->Root;
252 while (Current != NIL) {
256 * See if two entries are identical.
258 result = tree->Compare(Data, Current->Data);
261 * Don't replace the entry.
263 if (tree->replace_flag == 0) {
268 * Do replace the entry.
270 Current->Data = Data;
275 Current = (result < 0) ? Current->Left : Current->Right;
279 if ((X = malloc (sizeof(*X))) == NULL) {
289 /* insert node in tree */
291 if (tree->Compare(Data, Parent->Data) <= 0)
299 InsertFixup(tree, X);
305 static void DeleteFixup(rbtree_t *tree, rbnode_t *X)
307 /*************************************
308 * maintain red-black tree balance *
309 * after deleting node X *
310 *************************************/
312 while (X != tree->Root && X->Color == Black) {
313 if (X == X->Parent->Left) {
314 rbnode_t *W = X->Parent->Right;
315 if (W->Color == Red) {
317 X->Parent->Color = Red;
318 RotateLeft(tree, X->Parent);
319 W = X->Parent->Right;
321 if (W->Left->Color == Black && W->Right->Color == Black) {
325 if (W->Right->Color == Black) {
326 W->Left->Color = Black;
328 RotateRight(tree, W);
329 W = X->Parent->Right;
331 W->Color = X->Parent->Color;
332 X->Parent->Color = Black;
333 W->Right->Color = Black;
334 RotateLeft(tree, X->Parent);
338 rbnode_t *W = X->Parent->Left;
339 if (W->Color == Red) {
341 X->Parent->Color = Red;
342 RotateRight(tree, X->Parent);
345 if (W->Right->Color == Black && W->Left->Color == Black) {
349 if (W->Left->Color == Black) {
350 W->Right->Color = Black;
355 W->Color = X->Parent->Color;
356 X->Parent->Color = Black;
357 W->Left->Color = Black;
358 RotateRight(tree, X->Parent);
367 * Delete an element from the tree.
369 void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
373 /*****************************
374 * delete node Z from tree *
375 *****************************/
377 if (!Z || Z == NIL) return;
379 if (Z->Left == NIL || Z->Right == NIL) {
380 /* Y has a NIL node as a child */
383 /* find tree successor with a NIL node as a child */
385 while (Y->Left != NIL) Y = Y->Left;
388 /* X is Y's only child */
394 /* remove Y from the parent chain */
395 X->Parent = Y->Parent;
397 if (Y == Y->Parent->Left)
400 Y->Parent->Right = X;
404 if (Y != Z) Z->Data = Y->Data;
405 if (Y->Color == Black)
406 DeleteFixup(tree, X);
408 if (tree->freeNode) tree->freeNode(Y->Data);
413 * Find an element in the tree, returning the data, not the node.
415 void *rbtree_find(rbtree_t *tree, void *Data)
417 /*******************************
418 * find node containing Data *
419 *******************************/
421 rbnode_t *Current = tree->Root;
423 while (Current != NIL) {
424 int result = tree->Compare(Data, Current->Data);
427 return Current->Data;
429 Current = (result < 0) ?
430 Current->Left : Current->Right;
437 * Walk the tree, Pre-order
439 * We call ourselves recursively for each function, but that's OK,
440 * as the stack is only log(N) deep, which is ~12 entries deep.
442 static int WalkNodePreOrder(rbnode_t *X, int (*callback)(void *))
446 rcode = callback(X->Data);
447 if (rcode != 0) return rcode;
449 if (X->Left != NIL) {
450 rcode = WalkNodePreOrder(X->Left, callback);
451 if (rcode != 0) return rcode;
454 if (X->Right != NIL) {
455 rcode = WalkNodePreOrder(X->Right, callback);
456 if (rcode != 0) return rcode;
459 return 0; /* we know everything returned zero */
465 static int WalkNodeInOrder(rbnode_t *X, int (*callback)(void *))
469 if (X->Left != NIL) {
470 rcode = WalkNodeInOrder(X->Left, callback);
471 if (rcode != 0) return rcode;
474 rcode = callback(X->Data);
475 if (rcode != 0) return rcode;
477 if (X->Right != NIL) {
478 rcode = WalkNodeInOrder(X->Right, callback);
479 if (rcode != 0) return rcode;
482 return 0; /* we know everything returned zero */
489 static int WalkNodePostOrder(rbnode_t *X, int (*callback)(void *))
493 if (X->Left != NIL) {
494 rcode = WalkNodeInOrder(X->Left, callback);
495 if (rcode != 0) return rcode;
498 if (X->Right != NIL) {
499 rcode = WalkNodeInOrder(X->Right, callback);
500 if (rcode != 0) return rcode;
503 rcode = callback(X->Data);
504 if (rcode != 0) return rcode;
506 return 0; /* we know everything returned zero */
510 * Walk the entire tree. The callback function CANNOT modify
513 * The callback function should return 0 to continue walking.
514 * Any other value stops the walk, and is returned.
516 int rbtree_walk(rbtree_t *tree, int (*callback)(void *), NodeCallback order)
520 return WalkNodePreOrder(tree->Root, callback);
522 return WalkNodeInOrder(tree->Root, callback);
524 return WalkNodePostOrder(tree->Root, callback);