comparison src/redblack.c @ 125:e413158cae13

Add ushare project files.
author naoyan@johnstown.minaminoshima.org
date Sun, 03 Oct 2010 11:35:19 +0900
parents
children
comparison
equal deleted inserted replaced
124:9c7bc6c0327e 125:e413158cae13
1 static char rcsid[]="$Id: redblack.c,v 1.9 2003/10/24 01:31:21 damo Exp $";
2
3 /*
4 Redblack balanced tree algorithm
5 Copyright (C) Damian Ivereigh 2000
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version. See the file COPYING for details.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* Implement the red/black tree structure. It is designed to emulate
23 ** the standard tsearch() stuff. i.e. the calling conventions are
24 ** exactly the same
25 */
26
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include "redblack.h"
31
32 #define assert(expr)
33
34 /* Uncomment this if you would rather use a raw sbrk to get memory
35 ** (however the memory is never released again (only re-used). Can't
36 ** see any point in using this these days.
37 */
38 /* #define USE_SBRK */
39
40 enum nodecolour { BLACK, RED };
41
42 struct RB_ENTRY(node)
43 {
44 struct RB_ENTRY(node) *left; /* Left down */
45 struct RB_ENTRY(node) *right; /* Right down */
46 struct RB_ENTRY(node) *up; /* Up */
47 enum nodecolour colour; /* Node colour */
48 #ifdef RB_INLINE
49 RB_ENTRY(data_t) key; /* User's key (and data) */
50 #define RB_GET(x,y) &x->y
51 #define RB_SET(x,y,v) x->y = *(v)
52 #else
53 const RB_ENTRY(data_t) *key; /* Pointer to user's key (and data) */
54 #define RB_GET(x,y) x->y
55 #define RB_SET(x,y,v) x->y = v
56 #endif /* RB_INLINE */
57 };
58
59 /* Dummy (sentinel) node, so that we can make X->left->up = X
60 ** We then use this instead of NULL to mean the top or bottom
61 ** end of the rb tree. It is a black node.
62 **
63 ** Initialization of the last field in this initializer is left implicit
64 ** because it could be of any type. We count on the compiler to zero it.
65 */
66 struct RB_ENTRY(node) RB_ENTRY(_null)={&RB_ENTRY(_null), &RB_ENTRY(_null), &RB_ENTRY(_null), BLACK, &RB_ENTRY(_null)};
67 #define RBNULL (&RB_ENTRY(_null))
68
69 #if defined(USE_SBRK)
70
71 static struct RB_ENTRY(node) *RB_ENTRY(_alloc)();
72 static void RB_ENTRY(_free)(struct RB_ENTRY(node) *);
73
74 #else
75
76 static struct RB_ENTRY(node) *RB_ENTRY(_alloc)() {return (struct RB_ENTRY(node) *) malloc(sizeof(struct RB_ENTRY(node)));}
77 static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) {free(x);}
78
79 #endif
80
81 /* These functions are always needed */
82 static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
83 static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
84 static struct RB_ENTRY(node) *RB_ENTRY(_successor)(const struct RB_ENTRY(node) *);
85 static struct RB_ENTRY(node) *RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *);
86 static struct RB_ENTRY(node) *RB_ENTRY(_traverse)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *);
87
88 /* These functions may not be needed */
89 #ifndef no_lookup
90 static struct RB_ENTRY(node) *RB_ENTRY(_lookup)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *);
91 #endif
92
93 #ifndef no_destroy
94 static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *);
95 #endif
96
97 #ifndef no_delete
98 static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
99 static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
100 #endif
101
102 #ifndef no_walk
103 static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *, int);
104 #endif
105
106 #ifndef no_readlist
107 static RBLIST *RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *);
108 static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *);
109 static void RB_ENTRY(_closelist)(RBLIST *);
110 #endif
111
112 /*
113 ** OK here we go, the balanced tree stuff. The algorithm is the
114 ** fairly standard red/black taken from "Introduction to Algorithms"
115 ** by Cormen, Leiserson & Rivest. Maybe one of these days I will
116 ** fully understand all this stuff.
117 **
118 ** Basically a red/black balanced tree has the following properties:-
119 ** 1) Every node is either red or black (colour is RED or BLACK)
120 ** 2) A leaf (RBNULL pointer) is considered black
121 ** 3) If a node is red then its children are black
122 ** 4) Every path from a node to a leaf contains the same no
123 ** of black nodes
124 **
125 ** 3) & 4) above guarantee that the longest path (alternating
126 ** red and black nodes) is only twice as long as the shortest
127 ** path (all black nodes). Thus the tree remains fairly balanced.
128 */
129
130 /*
131 * Initialise a tree. Identifies the comparison routine and any config
132 * data that must be sent to it when called.
133 * Returns a pointer to the top of the tree.
134 */
135 #ifndef RB_CUSTOMIZE
136 RB_STATIC struct RB_ENTRY(tree) *
137 rbinit(int (*cmp)(const void *, const void *, const void *), const void *config)
138 #else
139 RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void)
140 #endif /* RB_CUSTOMIZE */
141 {
142 struct RB_ENTRY(tree) *retval;
143 char c;
144
145 c=rcsid[0]; /* This does nothing but shutup the -Wall */
146
147 if ((retval=(struct RB_ENTRY(tree) *) malloc(sizeof(struct RB_ENTRY(tree))))==NULL)
148 return(NULL);
149
150 #ifndef RB_CUSTOMIZE
151 retval->rb_cmp=cmp;
152 retval->rb_config=config;
153 #endif /* RB_CUSTOMIZE */
154 retval->rb_root=RBNULL;
155
156 return(retval);
157 }
158
159 #ifndef no_destroy
160 RB_STATIC void
161 RB_ENTRY(destroy)(struct RB_ENTRY(tree) *rbinfo)
162 {
163 if (rbinfo==NULL)
164 return;
165
166 if (rbinfo->rb_root!=RBNULL)
167 RB_ENTRY(_destroy)(rbinfo->rb_root);
168
169 free(rbinfo);
170 }
171 #endif /* no_destroy */
172
173 #ifndef no_search
174 RB_STATIC const RB_ENTRY(data_t) *
175 RB_ENTRY(search)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
176 {
177 struct RB_ENTRY(node) *x;
178
179 if (rbinfo==NULL)
180 return(NULL);
181
182 x=RB_ENTRY(_traverse)(1, key, rbinfo);
183
184 return((x==RBNULL) ? NULL : RB_GET(x, key));
185 }
186 #endif /* no_search */
187
188 #ifndef no_find
189 RB_STATIC const RB_ENTRY(data_t) *
190 RB_ENTRY(find)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
191 {
192 struct RB_ENTRY(node) *x;
193
194 if (rbinfo==NULL)
195 return(NULL);
196
197 /* If we have a NULL root (empty tree) then just return */
198 if (rbinfo->rb_root==RBNULL)
199 return(NULL);
200
201 x=RB_ENTRY(_traverse)(0, key, rbinfo);
202
203 return((x==RBNULL) ? NULL : RB_GET(x, key));
204 }
205 #endif /* no_find */
206
207 #ifndef no_delete
208 RB_STATIC const RB_ENTRY(data_t) *
209 RB_ENTRY(delete)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
210 {
211 struct RB_ENTRY(node) *x;
212 const RB_ENTRY(data_t) * y;
213
214 if (rbinfo==NULL)
215 return(NULL);
216
217 x=RB_ENTRY(_traverse)(0, key, rbinfo);
218
219 if (x==RBNULL)
220 {
221 return(NULL);
222 }
223 else
224 {
225 y=RB_GET(x, key);
226 RB_ENTRY(_delete)(&rbinfo->rb_root, x);
227
228 return(y);
229 }
230 }
231 #endif /* no_delete */
232
233 #ifndef no_walk
234 RB_STATIC void
235 RB_ENTRY(walk)(const struct RB_ENTRY(tree) *rbinfo, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg)
236 {
237 if (rbinfo==NULL)
238 return;
239
240 RB_ENTRY(_walk)(rbinfo->rb_root, action, arg, 0);
241 }
242 #endif /* no_walk */
243
244 #ifndef no_readlist
245 RB_STATIC RBLIST *
246 RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *rbinfo)
247 {
248 if (rbinfo==NULL)
249 return(NULL);
250
251 return(RB_ENTRY(_openlist)(rbinfo->rb_root));
252 }
253
254 RB_STATIC const RB_ENTRY(data_t) *
255 RB_ENTRY(readlist)(RBLIST *rblistp)
256 {
257 if (rblistp==NULL)
258 return(NULL);
259
260 return(RB_ENTRY(_readlist)(rblistp));
261 }
262
263 RB_STATIC void
264 RB_ENTRY(closelist)(RBLIST *rblistp)
265 {
266 if (rblistp==NULL)
267 return;
268
269 RB_ENTRY(_closelist)(rblistp);
270 }
271 #endif /* no_readlist */
272
273 #ifndef no_lookup
274 RB_STATIC const RB_ENTRY(data_t) *
275 RB_ENTRY(lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
276 {
277 struct RB_ENTRY(node) *x;
278
279 /* If we have a NULL root (empty tree) then just return NULL */
280 if (rbinfo==NULL || rbinfo->rb_root==NULL)
281 return(NULL);
282
283 x=RB_ENTRY(_lookup)(mode, key, rbinfo);
284
285 return((x==RBNULL) ? NULL : RB_GET(x, key));
286 }
287 #endif /* no_lookup */
288
289 /* --------------------------------------------------------------------- */
290
291 /* Search for and if not found and insert is true, will add a new
292 ** node in. Returns a pointer to the new node, or the node found
293 */
294 static struct RB_ENTRY(node) *
295 RB_ENTRY(_traverse)(int insert, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
296 {
297 struct RB_ENTRY(node) *x,*y,*z;
298 int cmp;
299 int found=0;
300 int cmpmods();
301
302 y=RBNULL; /* points to the parent of x */
303 x=rbinfo->rb_root;
304
305 /* walk x down the tree */
306 while(x!=RBNULL && found==0)
307 {
308 y=x;
309 /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
310 #ifndef RB_CUSTOMIZE
311 cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config);
312 #else
313 cmp=RB_CMP(key, RB_GET(x, key));
314 #endif /* RB_CUSTOMIZE */
315
316 if (cmp<0)
317 x=x->left;
318 else if (cmp>0)
319 x=x->right;
320 else
321 found=1;
322 }
323
324 if (found || !insert)
325 return(x);
326
327 if ((z=RB_ENTRY(_alloc)())==NULL)
328 {
329 /* Whoops, no memory */
330 return(RBNULL);
331 }
332
333 RB_SET(z, key, key);
334 z->up=y;
335 if (y==RBNULL)
336 {
337 rbinfo->rb_root=z;
338 }
339 else
340 {
341 #ifndef RB_CUSTOMIZE
342 cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key), rbinfo->rb_config);
343 #else
344 cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key));
345 #endif /* RB_CUSTOMIZE */
346 if (cmp<0)
347 y->left=z;
348 else
349 y->right=z;
350 }
351
352 z->left=RBNULL;
353 z->right=RBNULL;
354
355 /* colour this new node red */
356 z->colour=RED;
357
358 /* Having added a red node, we must now walk back up the tree balancing
359 ** it, by a series of rotations and changing of colours
360 */
361 x=z;
362
363 /* While we are not at the top and our parent node is red
364 ** N.B. Since the root node is garanteed black, then we
365 ** are also going to stop if we are the child of the root
366 */
367
368 while(x != rbinfo->rb_root && (x->up->colour == RED))
369 {
370 /* if our parent is on the left side of our grandparent */
371 if (x->up == x->up->up->left)
372 {
373 /* get the right side of our grandparent (uncle?) */
374 y=x->up->up->right;
375 if (y->colour == RED)
376 {
377 /* make our parent black */
378 x->up->colour = BLACK;
379 /* make our uncle black */
380 y->colour = BLACK;
381 /* make our grandparent red */
382 x->up->up->colour = RED;
383
384 /* now consider our grandparent */
385 x=x->up->up;
386 }
387 else
388 {
389 /* if we are on the right side of our parent */
390 if (x == x->up->right)
391 {
392 /* Move up to our parent */
393 x=x->up;
394 RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x);
395 }
396
397 /* make our parent black */
398 x->up->colour = BLACK;
399 /* make our grandparent red */
400 x->up->up->colour = RED;
401 /* right rotate our grandparent */
402 RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x->up->up);
403 }
404 }
405 else
406 {
407 /* everything here is the same as above, but
408 ** exchanging left for right
409 */
410
411 y=x->up->up->left;
412 if (y->colour == RED)
413 {
414 x->up->colour = BLACK;
415 y->colour = BLACK;
416 x->up->up->colour = RED;
417
418 x=x->up->up;
419 }
420 else
421 {
422 if (x == x->up->left)
423 {
424 x=x->up;
425 RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x);
426 }
427
428 x->up->colour = BLACK;
429 x->up->up->colour = RED;
430 RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x->up->up);
431 }
432 }
433 }
434
435 /* Set the root node black */
436 (rbinfo->rb_root)->colour = BLACK;
437
438 return(z);
439 }
440
441 #ifndef no_lookup
442 /* Search for a key according to mode (see redblack.h)
443 */
444 static struct RB_ENTRY(node) *
445 RB_ENTRY(_lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
446 {
447 struct RB_ENTRY(node) *x,*y;
448 int cmp=0;
449 int found=0;
450
451 y=RBNULL; /* points to the parent of x */
452 x=rbinfo->rb_root;
453
454 if (mode==RB_LUFIRST)
455 {
456 /* Keep going left until we hit a NULL */
457 while(x!=RBNULL)
458 {
459 y=x;
460 x=x->left;
461 }
462
463 return(y);
464 }
465 else if (mode==RB_LULAST)
466 {
467 /* Keep going right until we hit a NULL */
468 while(x!=RBNULL)
469 {
470 y=x;
471 x=x->right;
472 }
473
474 return(y);
475 }
476
477 /* walk x down the tree */
478 while(x!=RBNULL && found==0)
479 {
480 y=x;
481 /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
482 #ifndef RB_CUSTOMIZE
483 cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config);
484 #else
485 cmp=RB_CMP(key, RB_GET(x, key));
486 #endif /* RB_CUSTOMIZE */
487
488
489 if (cmp<0)
490 x=x->left;
491 else if (cmp>0)
492 x=x->right;
493 else
494 found=1;
495 }
496
497 if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ))
498 return(x);
499
500 if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV))
501 return(RBNULL);
502
503 if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT))
504 {
505 if (cmp>0)
506 return(RB_ENTRY(_successor)(y));
507 else
508 return(y);
509 }
510
511 if (mode==RB_LULTEQ || (!found && mode==RB_LULESS))
512 {
513 if (cmp<0)
514 return(RB_ENTRY(_predecessor)(y));
515 else
516 return(y);
517 }
518
519 if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT))
520 return(RB_ENTRY(_successor)(x));
521
522 if (mode==RB_LUPREV || (found && mode==RB_LULESS))
523 return(RB_ENTRY(_predecessor)(x));
524
525 /* Shouldn't get here */
526 return(RBNULL);
527 }
528 #endif /* no_lookup */
529
530 #ifndef no_destroy
531 /*
532 * Destroy all the elements blow us in the tree
533 * only useful as part of a complete tree destroy.
534 */
535 static void
536 RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x)
537 {
538 if (x!=RBNULL)
539 {
540 if (x->left!=RBNULL)
541 RB_ENTRY(_destroy)(x->left);
542 if (x->right!=RBNULL)
543 RB_ENTRY(_destroy)(x->right);
544 RB_ENTRY(_free)(x);
545 }
546 }
547 #endif /* no_destroy */
548
549 /*
550 ** Rotate our tree thus:-
551 **
552 ** X rb_left_rotate(X)---> Y
553 ** / \ / \
554 ** A Y <---rb_right_rotate(Y) X C
555 ** / \ / \
556 ** B C A B
557 **
558 ** N.B. This does not change the ordering.
559 **
560 ** We assume that neither X or Y is NULL
561 */
562
563 static void
564 RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x)
565 {
566 struct RB_ENTRY(node) *y;
567
568 assert(x!=RBNULL);
569 assert(x->right!=RBNULL);
570
571 y=x->right; /* set Y */
572
573 /* Turn Y's left subtree into X's right subtree (move B)*/
574 x->right = y->left;
575
576 /* If B is not null, set it's parent to be X */
577 if (y->left != RBNULL)
578 y->left->up = x;
579
580 /* Set Y's parent to be what X's parent was */
581 y->up = x->up;
582
583 /* if X was the root */
584 if (x->up == RBNULL)
585 {
586 *rootp=y;
587 }
588 else
589 {
590 /* Set X's parent's left or right pointer to be Y */
591 if (x == x->up->left)
592 {
593 x->up->left=y;
594 }
595 else
596 {
597 x->up->right=y;
598 }
599 }
600
601 /* Put X on Y's left */
602 y->left=x;
603
604 /* Set X's parent to be Y */
605 x->up = y;
606 }
607
608 static void
609 RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *y)
610 {
611 struct RB_ENTRY(node) *x;
612
613 assert(y!=RBNULL);
614 assert(y->left!=RBNULL);
615
616 x=y->left; /* set X */
617
618 /* Turn X's right subtree into Y's left subtree (move B) */
619 y->left = x->right;
620
621 /* If B is not null, set it's parent to be Y */
622 if (x->right != RBNULL)
623 x->right->up = y;
624
625 /* Set X's parent to be what Y's parent was */
626 x->up = y->up;
627
628 /* if Y was the root */
629 if (y->up == RBNULL)
630 {
631 *rootp=x;
632 }
633 else
634 {
635 /* Set Y's parent's left or right pointer to be X */
636 if (y == y->up->left)
637 {
638 y->up->left=x;
639 }
640 else
641 {
642 y->up->right=x;
643 }
644 }
645
646 /* Put Y on X's right */
647 x->right=y;
648
649 /* Set Y's parent to be X */
650 y->up = x;
651 }
652
653 /* Return a pointer to the smallest key greater than x
654 */
655 static struct RB_ENTRY(node) *
656 RB_ENTRY(_successor)(const struct RB_ENTRY(node) *x)
657 {
658 struct RB_ENTRY(node) *y;
659
660 if (x->right!=RBNULL)
661 {
662 /* If right is not NULL then go right one and
663 ** then keep going left until we find a node with
664 ** no left pointer.
665 */
666 for (y=x->right; y->left!=RBNULL; y=y->left);
667 }
668 else
669 {
670 /* Go up the tree until we get to a node that is on the
671 ** left of its parent (or the root) and then return the
672 ** parent.
673 */
674 y=x->up;
675 while(y!=RBNULL && x==y->right)
676 {
677 x=y;
678 y=y->up;
679 }
680 }
681 return(y);
682 }
683
684 /* Return a pointer to the largest key smaller than x
685 */
686 static struct RB_ENTRY(node) *
687 RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *x)
688 {
689 struct RB_ENTRY(node) *y;
690
691 if (x->left!=RBNULL)
692 {
693 /* If left is not NULL then go left one and
694 ** then keep going right until we find a node with
695 ** no right pointer.
696 */
697 for (y=x->left; y->right!=RBNULL; y=y->right);
698 }
699 else
700 {
701 /* Go up the tree until we get to a node that is on the
702 ** right of its parent (or the root) and then return the
703 ** parent.
704 */
705 y=x->up;
706 while(y!=RBNULL && x==y->left)
707 {
708 x=y;
709 y=y->up;
710 }
711 }
712 return(y);
713 }
714
715 #ifndef no_delete
716 /* Delete the node z, and free up the space
717 */
718 static void
719 RB_ENTRY(_delete)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *z)
720 {
721 struct RB_ENTRY(node) *x, *y;
722
723 if (z->left == RBNULL || z->right == RBNULL)
724 y=z;
725 else
726 y=RB_ENTRY(_successor)(z);
727
728 if (y->left != RBNULL)
729 x=y->left;
730 else
731 x=y->right;
732
733 x->up = y->up;
734
735 if (y->up == RBNULL)
736 {
737 *rootp=x;
738 }
739 else
740 {
741 if (y==y->up->left)
742 y->up->left = x;
743 else
744 y->up->right = x;
745 }
746
747 if (y!=z)
748 {
749 RB_SET(z, key, RB_GET(y, key));
750 }
751
752 if (y->colour == BLACK)
753 RB_ENTRY(_delete_fix)(rootp, x);
754
755 RB_ENTRY(_free)(y);
756 }
757
758 /* Restore the reb-black properties after a delete */
759 static void
760 RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x)
761 {
762 struct RB_ENTRY(node) *w;
763
764 while (x!=*rootp && x->colour==BLACK)
765 {
766 if (x==x->up->left)
767 {
768 w=x->up->right;
769 if (w->colour==RED)
770 {
771 w->colour=BLACK;
772 x->up->colour=RED;
773 rb_left_rotate(rootp, x->up);
774 w=x->up->right;
775 }
776
777 if (w->left->colour==BLACK && w->right->colour==BLACK)
778 {
779 w->colour=RED;
780 x=x->up;
781 }
782 else
783 {
784 if (w->right->colour == BLACK)
785 {
786 w->left->colour=BLACK;
787 w->colour=RED;
788 RB_ENTRY(_right_rotate)(rootp, w);
789 w=x->up->right;
790 }
791
792
793 w->colour=x->up->colour;
794 x->up->colour = BLACK;
795 w->right->colour = BLACK;
796 RB_ENTRY(_left_rotate)(rootp, x->up);
797 x=*rootp;
798 }
799 }
800 else
801 {
802 w=x->up->left;
803 if (w->colour==RED)
804 {
805 w->colour=BLACK;
806 x->up->colour=RED;
807 RB_ENTRY(_right_rotate)(rootp, x->up);
808 w=x->up->left;
809 }
810
811 if (w->right->colour==BLACK && w->left->colour==BLACK)
812 {
813 w->colour=RED;
814 x=x->up;
815 }
816 else
817 {
818 if (w->left->colour == BLACK)
819 {
820 w->right->colour=BLACK;
821 w->colour=RED;
822 RB_ENTRY(_left_rotate)(rootp, w);
823 w=x->up->left;
824 }
825
826 w->colour=x->up->colour;
827 x->up->colour = BLACK;
828 w->left->colour = BLACK;
829 RB_ENTRY(_right_rotate)(rootp, x->up);
830 x=*rootp;
831 }
832 }
833 }
834
835 x->colour=BLACK;
836 }
837 #endif /* no_delete */
838
839 #ifndef no_walk
840 static void
841 RB_ENTRY(_walk)(const struct RB_ENTRY(node) *x, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg, int level)
842 {
843 if (x==RBNULL)
844 return;
845
846 if (x->left==RBNULL && x->right==RBNULL)
847 {
848 /* leaf */
849 (*action)(RB_GET(x, key), leaf, level, arg);
850 }
851 else
852 {
853 (*action)(RB_GET(x, key), preorder, level, arg);
854
855 RB_ENTRY(_walk)(x->left, action, arg, level+1);
856
857 (*action)(RB_GET(x, key), postorder, level, arg);
858
859 RB_ENTRY(_walk)(x->right, action, arg, level+1);
860
861 (*action)(RB_GET(x, key), endorder, level, arg);
862 }
863 }
864 #endif /* no_walk */
865
866 #ifndef no_readlist
867 static RBLIST *
868 RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *rootp)
869 {
870 RBLIST *rblistp;
871
872 rblistp=(RBLIST *) malloc(sizeof(RBLIST));
873 if (!rblistp)
874 return(NULL);
875
876 rblistp->rootp=rootp;
877 rblistp->nextp=rootp;
878
879 if (rootp!=RBNULL)
880 {
881 while(rblistp->nextp->left!=RBNULL)
882 {
883 rblistp->nextp=rblistp->nextp->left;
884 }
885 }
886
887 return(rblistp);
888 }
889
890 static const RB_ENTRY(data_t) *
891 RB_ENTRY(_readlist)(RBLIST *rblistp)
892 {
893 const RB_ENTRY(data_t) *key=NULL;
894
895 if (rblistp!=NULL && rblistp->nextp!=RBNULL)
896 {
897 key=RB_GET(rblistp->nextp, key);
898 rblistp->nextp=RB_ENTRY(_successor)(rblistp->nextp);
899 }
900
901 return(key);
902 }
903
904 static void
905 rb_closelist(RBLIST *rblistp)
906 {
907 if (rblistp)
908 free(rblistp);
909 }
910 #endif /* no_readlist */
911
912 #if defined(RB_USE_SBRK)
913 /* Allocate space for our nodes, allowing us to get space from
914 ** sbrk in larger chucks.
915 */
916 static struct RB_ENTRY(node) *rbfreep=NULL;
917
918 #define RB_ENTRY(NODE)ALLOC_CHUNK_SIZE 1000
919 static struct RB_ENTRY(node) *
920 RB_ENTRY(_alloc)()
921 {
922 struct RB_ENTRY(node) *x;
923 int i;
924
925 if (rbfreep==NULL)
926 {
927 /* must grab some more space */
928 rbfreep=(struct RB_ENTRY(node) *) sbrk(sizeof(struct RB_ENTRY(node)) * RB_ENTRY(NODE)ALLOC_CHUNK_SIZE);
929
930 if (rbfreep==(struct RB_ENTRY(node) *) -1)
931 {
932 return(NULL);
933 }
934
935 /* tie them together in a linked list (use the up pointer) */
936 for (i=0, x=rbfreep; i<RB_ENTRY(NODE)ALLOC_CHUNK_SIZE-1; i++, x++)
937 {
938 x->up = (x+1);
939 }
940 x->up=NULL;
941 }
942
943 x=rbfreep;
944 rbfreep = rbfreep->up;
945 #ifdef RB_ALLOC
946 RB_ALLOC(ACCESS(x, key));
947 #endif /* RB_ALLOC */
948 return(x);
949 }
950
951 /* free (dealloc) an RB_ENTRY(node) structure - add it onto the front of the list
952 ** N.B. RB_ENTRY(node) need not have been allocated through rb_alloc()
953 */
954 static void
955 RB_ENTRY(_free)(struct RB_ENTRY(node) *x)
956 {
957 #ifdef RB_FREE
958 RB_FREE(ACCESS(x, key));
959 #endif /* RB_FREE */
960 x->up=rbfreep;
961 rbfreep=x;
962 }
963
964 #endif
965
966 #if 0
967 int
968 RB_ENTRY(_check)(struct RB_ENTRY(node) *rootp)
969 {
970 if (rootp==NULL || rootp==RBNULL)
971 return(0);
972
973 if (rootp->up!=RBNULL)
974 {
975 fprintf(stderr, "Root up pointer not RBNULL");
976 dumptree(rootp, 0);
977 return(1);
978 }
979
980 if (RB_ENTRY(_check)1(rootp))
981 {
982 RB_ENTRY(dumptree)(rootp, 0);
983 return(1);
984 }
985
986 if (RB_ENTRY(count_black)(rootp)==-1)
987 {
988 RB_ENTRY(dumptree)(rootp, 0);
989 return(-1);
990 }
991
992 return(0);
993 }
994
995 int
996 RB_ENTRY(_check1)(struct RB_ENTRY(node) *x)
997 {
998 if (x->left==NULL || x->right==NULL)
999 {
1000 fprintf(stderr, "Left or right is NULL");
1001 return(1);
1002 }
1003
1004 if (x->colour==RED)
1005 {
1006 if (x->left->colour!=BLACK && x->right->colour!=BLACK)
1007 {
1008 fprintf(stderr, "Children of red node not both black, x=%ld", x);
1009 return(1);
1010 }
1011 }
1012
1013 if (x->left != RBNULL)
1014 {
1015 if (x->left->up != x)
1016 {
1017 fprintf(stderr, "x->left->up != x, x=%ld", x);
1018 return(1);
1019 }
1020
1021 if (rb_check1(x->left))
1022 return(1);
1023 }
1024
1025 if (x->right != RBNULL)
1026 {
1027 if (x->right->up != x)
1028 {
1029 fprintf(stderr, "x->right->up != x, x=%ld", x);
1030 return(1);
1031 }
1032
1033 if (rb_check1(x->right))
1034 return(1);
1035 }
1036 return(0);
1037 }
1038
1039 RB_ENTRY(count_black)(struct RB_ENTRY(node) *x)
1040 {
1041 int nleft, nright;
1042
1043 if (x==RBNULL)
1044 return(1);
1045
1046 nleft=RB_ENTRY(count_black)(x->left);
1047 nright=RB_ENTRY(count_black)(x->right);
1048
1049 if (nleft==-1 || nright==-1)
1050 return(-1);
1051
1052 if (nleft != nright)
1053 {
1054 fprintf(stderr, "Black count not equal on left & right, x=%ld", x);
1055 return(-1);
1056 }
1057
1058 if (x->colour == BLACK)
1059 {
1060 nleft++;
1061 }
1062
1063 return(nleft);
1064 }
1065
1066 RB_ENTRY(dumptree)(struct RB_ENTRY(node) *x, int n)
1067 {
1068 char *prkey();
1069
1070 if (x!=NULL && x!=RBNULL)
1071 {
1072 n++;
1073 fprintf(stderr, "Tree: %*s %ld: left=%ld, right=%ld, colour=%s, key=%s",
1074 n,
1075 "",
1076 x,
1077 x->left,
1078 x->right,
1079 (x->colour==BLACK) ? "BLACK" : "RED",
1080 prkey(RB_GET(x, key)));
1081
1082 RB_ENTRY(dumptree)(x->left, n);
1083 RB_ENTRY(dumptree)(x->right, n);
1084 }
1085 }
1086 #endif
1087
1088 /*
1089 * $Log: redblack.c,v $
1090 * Revision 1.9 2003/10/24 01:31:21 damo
1091 * Patches from Eric Raymond: %prefix is implemented.  Various other small
1092 * changes avoid stepping on global namespaces and improve the documentation.
1093 *
1094 * Revision 1.8 2002/08/26 05:33:47 damo
1095 * Some minor fixes:-
1096 * Stopped ./configure warning about stuff being in the wrong order
1097 * Fixed compiler warning about const (not sure about this)
1098 * Changed directory of redblack.c in documentation
1099 *
1100 * Revision 1.7 2002/08/26 03:11:40 damo
1101 * Fixed up a bunch of compiler warnings when compiling example4
1102 *
1103 * Tidies up the Makefile.am & Specfile.
1104 *
1105 * Renamed redblack to rbgen
1106 *
1107 * Revision 1.6 2002/08/26 01:03:35 damo
1108 * Patch from Eric Raymond to change the way the library is used:-
1109 *
1110 * Eric's idea is to convert libredblack into a piece of in-line code
1111 * generated by another program. This should be faster, smaller and easier
1112 * to use.
1113 *
1114 * This is the first check-in of his code before I start futzing with it!
1115 *
1116 * Revision 1.5 2002/01/30 07:54:53 damo
1117 * Fixed up the libtool versioning stuff (finally)
1118 * Fixed bug 500600 (not detecting a NULL return from malloc)
1119 * Fixed bug 509485 (no longer needs search.h)
1120 * Cleaned up debugging section
1121 * Allow multiple inclusions of redblack.h
1122 * Thanks to Matthias Andree for reporting (and fixing) these
1123 *
1124 * Revision 1.4 2000/06/06 14:43:43 damo
1125 * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk.
1126 * Added two new examples
1127 *
1128 * Revision 1.3 2000/05/24 06:45:27 damo
1129 * Converted everything over to using const
1130 * Added a new example1.c file to demonstrate the worst case scenario
1131 * Minor fixups of the spec file
1132 *
1133 * Revision 1.2 2000/05/24 06:17:10 damo
1134 * Fixed up the License (now the LGPL)
1135 *
1136 * Revision 1.1 2000/05/24 04:15:53 damo
1137 * Initial import of files. Versions are now all over the place. Oh well
1138 *
1139 */
1140