Mercurial > pt1.oyama
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 |