1 static const char CVSID
[] = "$Id: rbTree.c,v 1.7 2002/07/11 21:18:10 slobasso Exp $";
2 /*******************************************************************************
4 * rbTree.c -- Nirvana editor red-black balanced binary tree *
6 * Copyright (C) 2001 Mark Edel *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
20 * Place, Suite 330, Boston, MA 02111-1307 USA *
22 * Nirvana Text Editor *
25 * Written by Mark Edel *
27 *******************************************************************************/
30 ** rbTree is a red-black balanced binary tree
31 ** the base node holds the leftmost, rightmost and root pointers
36 #include "../config.h"
43 /*#define RBTREE_TEST_CODE*/
44 #ifdef RBTREE_TEST_CODE
53 #define rbTreeNodeRed 0
54 #define rbTreeNodeBlack 1
59 static void rotateLeft(rbTreeNode
*x
, rbTreeNode
**root
)
61 rbTreeNode
*y
= x
->right
;
63 if (y
->left
!= NULL
) {
66 y
->parent
= x
->parent
;
71 else if (x
== x
->parent
->left
) {
82 ** rotate a node right
84 static void rotateRight(rbTreeNode
*x
, rbTreeNode
**root
)
86 rbTreeNode
*y
= x
->left
;
88 if (y
->right
!= NULL
) {
91 y
->parent
= x
->parent
;
96 else if (x
== x
->parent
->right
) {
107 ** balance tree after an insert of node x
109 static void insertBalance(rbTreeNode
*x
, rbTreeNode
**root
)
111 x
->color
= rbTreeNodeRed
;
112 while (x
!= *root
&& x
->parent
->color
== rbTreeNodeRed
) {
113 if (x
->parent
== x
->parent
->parent
->left
) {
114 rbTreeNode
*y
= x
->parent
->parent
->right
;
115 if (y
&& y
->color
== rbTreeNodeRed
) {
116 x
->parent
->color
= rbTreeNodeBlack
;
117 y
->color
= rbTreeNodeBlack
;
118 x
->parent
->parent
->color
= rbTreeNodeRed
;
119 x
= x
->parent
->parent
;
122 if (x
== x
->parent
->right
) {
126 x
->parent
->color
= rbTreeNodeBlack
;
127 x
->parent
->parent
->color
= rbTreeNodeRed
;
128 rotateRight(x
->parent
->parent
, root
);
132 rbTreeNode
*y
= x
->parent
->parent
->left
;
133 if (y
&& y
->color
== rbTreeNodeRed
) {
134 x
->parent
->color
= rbTreeNodeBlack
;
135 y
->color
= rbTreeNodeBlack
;
136 x
->parent
->parent
->color
= rbTreeNodeRed
;
137 x
= x
->parent
->parent
;
140 if (x
== x
->parent
->left
) {
142 rotateRight(x
, root
);
144 x
->parent
->color
= rbTreeNodeBlack
;
145 x
->parent
->parent
->color
= rbTreeNodeRed
;
146 rotateLeft(x
->parent
->parent
, root
);
150 (*root
)->color
= rbTreeNodeBlack
;
154 ** returns the leftmost node (the beginning of the sorted list)
156 rbTreeNode
*rbTreeBegin(rbTreeNode
*base
)
162 ** returns the rightmost node (the end of the sorted list)
164 rbTreeNode
*rbTreeReverseBegin(rbTreeNode
*base
)
170 ** search for a node and return it's pointer, NULL if not found
172 rbTreeNode
*rbTreeFind(rbTreeNode
*base
, rbTreeNode
*searchNode
,
173 rbTreeCompareNodeCB compareRecords
)
175 rbTreeNode
*foundNode
= NULL
;
176 rbTreeNode
*current
= base
->parent
;
177 while(current
!= NULL
) {
178 int compareResult
= compareRecords(searchNode
, current
);
180 if (compareResult
< 0) {
181 current
= current
->left
;
183 else if (compareResult
> 0) {
184 current
= current
->right
;
195 ** insert a node into the tree and rebalance it
196 ** if a duplicate is found copy the new data over it
197 ** returns the new node
199 rbTreeNode
*rbTreeInsert(rbTreeNode
*base
, rbTreeNode
*searchNode
,
200 rbTreeCompareNodeCB compareRecords
,
201 rbTreeAllocateNodeCB allocateNode
,
202 rbTreeCopyToNodeCB copyToNode
)
204 rbTreeNode
*current
, *parent
, *x
;
205 int fromLeft
= 0, foundMatch
= 0;
207 current
= base
->parent
;
210 while(current
!= NULL
) {
211 int compareResult
= compareRecords(searchNode
, current
);
213 if (compareResult
< 0) {
215 current
= current
->left
;
218 else if (compareResult
> 0) {
220 current
= current
->right
;
225 if (!copyToNode(x
, searchNode
)) {
234 x
= allocateNode(searchNode
);
239 x
->color
= rbTreeNodeRed
;
253 if (x
->parent
== base
->left
&& (x
->parent
== NULL
|| x
->parent
->left
== x
)) {
256 if (x
->parent
== base
->right
&& (x
->parent
== NULL
|| x
->parent
->right
== x
)) {
259 insertBalance(x
, &base
->parent
);
266 ** unlink a node from the tree and rebalance it.
267 ** returns the removed node pointer
269 rbTreeNode
*rbTreeUnlinkNode(rbTreeNode
*base
, rbTreeNode
*z
)
272 rbTreeNode
*x
, *y
, *x_parent
;
275 if (y
->left
== NULL
) {
277 if (y
== base
->left
) {
278 base
->left
= rbTreeNext(y
);
282 if (y
->right
== NULL
) {
284 if (y
== base
->right
) {
285 base
->right
= rbTreePrevious(y
);
290 while (y
->left
!= NULL
) {
300 x_parent
= y
->parent
;
302 x
->parent
= y
->parent
;
306 z
->right
->parent
= y
;
311 if (base
->parent
== z
) {
314 else if (z
->parent
->left
== z
) {
318 z
->parent
->right
= y
;
320 y
->parent
= z
->parent
;
322 swapColor
= y
->color
;
324 z
->color
= swapColor
;
329 x_parent
= y
->parent
;
331 x
->parent
= y
->parent
;
333 if (base
->parent
== z
) {
337 if (z
->parent
->left
== z
) {
341 z
->parent
->right
= x
;
348 if (y
->color
!= rbTreeNodeRed
) {
349 while (x
!= base
->parent
&& (x
== NULL
|| x
->color
== rbTreeNodeBlack
)) {
350 if (x
== x_parent
->left
) {
351 rbTreeNode
*w
= x_parent
->right
;
352 if (w
->color
== rbTreeNodeRed
) {
353 w
->color
= rbTreeNodeBlack
;
354 x_parent
->color
= rbTreeNodeRed
;
355 rotateLeft(x_parent
, &base
->parent
);
358 if ((w
->left
== NULL
||
359 w
->left
->color
== rbTreeNodeBlack
) &&
361 w
->right
->color
== rbTreeNodeBlack
)) {
363 w
->color
= rbTreeNodeRed
;
365 x_parent
= x_parent
->parent
;
367 if (w
->right
== NULL
||
368 w
->right
->color
== rbTreeNodeBlack
) {
371 w
->left
->color
= rbTreeNodeBlack
;
373 w
->color
= rbTreeNodeRed
;
374 rotateRight(w
, &base
->parent
);
377 w
->color
= x_parent
->color
;
378 x_parent
->color
= rbTreeNodeBlack
;
380 w
->right
->color
= rbTreeNodeBlack
;
382 rotateLeft(x_parent
, &base
->parent
);
387 rbTreeNode
*w
= x_parent
->left
;
388 if (w
->color
== rbTreeNodeRed
) {
389 w
->color
= rbTreeNodeBlack
;
390 x_parent
->color
= rbTreeNodeRed
;
391 rotateRight(x_parent
, &base
->parent
);
394 if ((w
->right
== NULL
||
395 w
->right
->color
== rbTreeNodeBlack
) &&
397 w
->left
->color
== rbTreeNodeBlack
)) {
399 w
->color
= rbTreeNodeRed
;
401 x_parent
= x_parent
->parent
;
404 if (w
->left
== NULL
||
405 w
->left
->color
== rbTreeNodeBlack
) {
408 w
->right
->color
= rbTreeNodeBlack
;
410 w
->color
= rbTreeNodeRed
;
411 rotateLeft(w
, &base
->parent
);
414 w
->color
= x_parent
->color
;
415 x_parent
->color
= rbTreeNodeBlack
;
417 w
->left
->color
= rbTreeNodeBlack
;
419 rotateRight(x_parent
, &base
->parent
);
425 x
->color
= rbTreeNodeBlack
;
432 ** delete an already found node and dispose it
434 void rbTreeDeleteNode(rbTreeNode
*base
, rbTreeNode
*foundNode
,
435 rbTreeDisposeNodeCB disposeNode
)
437 disposeNode(rbTreeUnlinkNode(base
, foundNode
));
441 ** search for a node and remove it from the tree
442 ** disposing the removed node
443 ** returns 1 if a node was found, otherwise 0
445 int rbTreeDelete(rbTreeNode
*base
, rbTreeNode
*searchNode
,
446 rbTreeCompareNodeCB compareRecords
,
447 rbTreeDisposeNodeCB disposeNode
)
452 z
= rbTreeFind(base
, searchNode
, compareRecords
);
454 rbTreeDeleteNode(base
, z
, disposeNode
);
461 ** move an iterator foreward one element
462 ** note that a valid pointer must be passed,
463 ** passing NULL will result in unpredictable results
465 rbTreeNode
*rbTreeNext(rbTreeNode
*x
)
467 if (x
->right
!= NULL
) {
469 while (x
->left
!= NULL
) {
478 } while (x
&& fromX
== x
->right
);
484 ** move an iterator back one element
485 ** note that a valid pointer must be passed,
486 ** passing NULL will result in unpredictable results
488 rbTreeNode
*rbTreePrevious(rbTreeNode
*x
)
490 if (x
->left
!= NULL
) {
492 while (x
->right
!= NULL
) {
501 } while (x
&& fromX
== x
->left
);
507 ** returns the number of real data nodes in the tree, not counting
508 ** the base node since it contains no data
510 int rbTreeSize(rbTreeNode
*base
)
516 ** Allocate a new red-black tree using an empty node to hold pointers
518 rbTreeNode
*rbTreeNew(rbTreeAllocateEmptyNodeCB allocateEmptyNode
)
520 rbTreeNode
*rootStorage
= allocateEmptyNode();
522 rootStorage
->left
= NULL
; /* leftmost node */
523 rootStorage
->right
= NULL
; /* rightmost node */
524 rootStorage
->parent
= NULL
; /* root node */
525 rootStorage
->color
= 0; /* node count */
531 ** iterate through all nodes, unlinking and disposing them
532 ** extra effort is made to maintain all links, the size, and
533 ** leftmost/rightmost pointers, so that the tree can be dumped
534 ** when debugging problems. We could probably ifdef some of this
535 ** since it goes unused most of the time
536 ** the tree is not kept balanced since all nodes will be removed
538 void rbTreeDispose(rbTreeNode
*base
, rbTreeDisposeNodeCB disposeNode
)
540 rbTreeNode
*iter
= rbTreeBegin(base
);
541 while (iter
!= NULL
) {
542 rbTreeNode
*nextIter
= rbTreeNext(iter
);
545 if (iter
->parent
->left
== iter
) {
546 iter
->parent
->left
= iter
->right
;
549 iter
->parent
->right
= iter
->right
;
552 if (iter
->right
!= NULL
) {
553 iter
->right
->parent
= iter
->parent
;
555 base
->left
= nextIter
;
556 if (base
->right
== iter
) {
560 if (base
->parent
== iter
) {
561 base
->parent
= nextIter
;
570 #ifdef RBTREE_TEST_CODE
571 /* ================================================================== */
574 ** code to test basic stuff of tree routines
577 typedef struct TestNode
{
578 rbTreeNode nodePointers
; /* MUST BE FIRST MEMBER */
584 static int rbTreeCompareNode_TestNode(rbTreeNode
*left
, rbTreeNode
*right
)
586 return(strcmp(((TestNode
*)left
)->key
, ((TestNode
*)right
)->key
));
589 static rbTreeNode
*rbTreeAllocateNode_TestNode(rbTreeNode
*src
)
591 TestNode
*newNode
= malloc(sizeof(TestNode
));
593 newNode
->str
= malloc(strlen(((TestNode
*)src
)->str
) + 1);
595 strcpy(newNode
->str
, ((TestNode
*)src
)->str
);
597 newNode
->key
= malloc(strlen(((TestNode
*)src
)->key
) + 1);
599 strcpy(newNode
->key
, ((TestNode
*)src
)->key
);
614 return((rbTreeNode
*)newNode
);
617 rbTreeNode
*rbTreeAllocateEmptyNodeCB_TestNode(void)
619 TestNode
*newNode
= malloc(sizeof(TestNode
));
624 return((rbTreeNode
*)newNode
);
627 static void rbTreeDisposeNode_TestNode(rbTreeNode
*src
)
630 if (((TestNode
*)src
)->str
) {
631 free(((TestNode
*)src
)->str
);
632 ((TestNode
*)src
)->str
= NULL
;
634 if (((TestNode
*)src
)->key
) {
635 free(((TestNode
*)src
)->key
);
636 ((TestNode
*)src
)->key
= NULL
;
638 src
->left
= (void *)-1;
639 src
->right
= (void *)-1;
640 src
->parent
= (void *)-1;
641 src
->color
= rbTreeNodeBlack
;
647 static int rbTreeCopyToNode_TestNode(rbTreeNode
*dst
, rbTreeNode
*src
)
652 newValues
.str
= malloc(strlen(((TestNode
*)src
)->str
) + 1);
654 strcpy(newValues
.str
, ((TestNode
*)src
)->str
);
656 newValues
.key
= malloc(strlen(((TestNode
*)src
)->key
) + 1);
658 strcpy(newValues
.key
, ((TestNode
*)src
)->key
);
660 ((TestNode
*)dst
)->str
= newValues
.str
;
661 ((TestNode
*)dst
)->key
= newValues
.key
;
666 newValues
.str
= NULL
;
672 static void DumpTree(rbTreeNode
*base
)
676 newNode
= rbTreeBegin(base
);
677 while (newNode
!= NULL
) {
678 rbTreeNode
*nextNode
= rbTreeNext(newNode
);
680 printf("[%s] = \"%s\"\n", ((TestNode
*)newNode
)->key
, ((TestNode
*)newNode
)->str
);
681 printf("[%x] l[%x] r[%x] p[%x] <%s>\n", (int)newNode
, (int)newNode
->left
, (int)newNode
->right
, (int)newNode
->parent
, ((newNode
->color
== rbTreeNodeBlack
)?"Black":"Red"));
687 int main(int argc
, char **argv
)
689 rbTreeNode
*base
, *newNode
;
691 char tmpkey
[20], tmpValue
[40];
694 searchNode
.key
= tmpkey
;
695 searchNode
.str
= tmpValue
;
697 base
= rbTreeNew(rbTreeAllocateEmptyNodeCB_TestNode
);
699 printf("Failed New!!!\n");
702 for (i
= 0; i
< 100; ++i
) {
703 sprintf(tmpkey
, "%d", i
);
704 sprintf(tmpValue
, "<%d>", i
* i
);
706 newNode
= rbTreeInsert(base
, (rbTreeNode
*)&searchNode
,
707 rbTreeCompareNode_TestNode
,
708 rbTreeAllocateNode_TestNode
,
709 rbTreeCopyToNode_TestNode
);
711 printf("Failed!!!\n");
716 newNode
= rbTreeBegin(base
);
717 while (newNode
!= NULL
) {
718 rbTreeNode
*nextNode
= rbTreeNext(newNode
);
720 printf("[%s] = \"%s\"\n", ((TestNode
*)newNode
)->key
, ((TestNode
*)newNode
)->str
);
722 if (strlen(((TestNode
*)newNode
)->str
) < 7) {
725 printf("Deleting [%s]\n", ((TestNode
*)newNode
)->key
);
726 didDelete
= rbTreeDelete(base
, newNode
,
727 rbTreeCompareNode_TestNode
, rbTreeDisposeNode_TestNode
);
728 printf("delete result = %d\n", didDelete
);
734 printf("Tree Size = %d\n", rbTreeSize(base
));
735 printf("\n++++++++++++++++\n");
737 printf("\n++++++++++++++++\n");
739 rbTreeDispose(base
, rbTreeDisposeNode_TestNode
);