sys_stat: Fix 'implicit declaration of function' warning on OS/2 kLIBC.
[gnulib.git] / lib / gl_rbtree_ordered.h
blob841c887e7634e3a974d7ab8f9ccd6624e0832fb0
1 /* Ordered {set,map} data type implemented by a binary tree.
2 Copyright (C) 2006-2007, 2009-2019 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* A red-black tree is a binary tree where every node is colored black or
19 red such that
20 1. The root is black.
21 2. No red node has a red parent.
22 Or equivalently: No red node has a red child.
23 3. All paths from the root down to any NULL endpoint contain the same
24 number of black nodes.
25 Let's call this the "black-height" bh of the tree. It follows that every
26 such path contains exactly bh black and between 0 and bh red nodes. (The
27 extreme cases are a path containing only black nodes, and a path colored
28 alternately black-red-black-red-...-black-red.) The height of the tree
29 therefore is >= bh, <= 2*bh.
32 /* Color of a node. */
33 typedef enum color { BLACK, RED } color_t;
35 /* Tree node implementation, valid for this file only. */
36 struct NODE_IMPL
38 struct NODE_IMPL *left; /* left branch, or NULL */
39 struct NODE_IMPL *right; /* right branch, or NULL */
40 /* Parent pointer, or NULL. The parent pointer is not needed for most
41 operations. It is needed so that a NODE_T can be returned without
42 memory allocation, on which the functions <container>_remove_node,
43 <container>_add_before, <container>_add_after can be implemented. */
44 struct NODE_IMPL *parent;
45 color_t color; /* node's color */
46 NODE_PAYLOAD_FIELDS
48 typedef struct NODE_IMPL * NODE_T;
50 /* Concrete CONTAINER_IMPL type, valid for this file only. */
51 struct CONTAINER_IMPL
53 struct CONTAINER_IMPL_BASE base;
54 struct NODE_IMPL *root; /* root node or NULL */
55 size_t count; /* number of nodes */
58 /* A red-black tree of height h has a black-height bh >= ceil(h/2) and
59 therefore at least 2^ceil(h/2) - 1 elements. So, h <= 116 (because a tree
60 of height h >= 117 would have at least 2^59 - 1 elements, and because even
61 on 64-bit machines,
62 sizeof (NODE_IMPL) * (2^59 - 1) > 2^64
63 this would exceed the address space of the machine. */
64 #define MAXHEIGHT 116
66 /* Rotate left a subtree.
68 B D
69 / \ / \
70 A D --> B E
71 / \ / \
72 C E A C
74 Change the tree structure, update the branch sizes.
75 The caller must update the colors and register D as child of its parent. */
76 static NODE_T
77 rotate_left (NODE_T b_node, NODE_T d_node)
79 NODE_T c_node = d_node->left;
81 b_node->right = c_node;
82 d_node->left = b_node;
84 d_node->parent = b_node->parent;
85 b_node->parent = d_node;
86 if (c_node != NULL)
87 c_node->parent = b_node;
89 return d_node;
92 /* Rotate right a subtree.
94 D B
95 / \ / \
96 B E --> A D
97 / \ / \
98 A C C E
100 Change the tree structure, update the branch sizes.
101 The caller must update the colors and register B as child of its parent. */
102 static NODE_T
103 rotate_right (NODE_T b_node, NODE_T d_node)
105 NODE_T c_node = b_node->right;
107 d_node->left = c_node;
108 b_node->right = d_node;
110 b_node->parent = d_node->parent;
111 d_node->parent = b_node;
112 if (c_node != NULL)
113 c_node->parent = d_node;
115 return b_node;
118 /* Ensure the tree is balanced, after an insertion operation.
119 Also assigns node->color.
120 parent is the given node's parent, known to be non-NULL. */
121 static void
122 rebalance_after_add (CONTAINER_T container, NODE_T node, NODE_T parent)
124 for (;;)
126 /* At this point, parent = node->parent != NULL.
127 Think of node->color being RED (although node->color is not yet
128 assigned.) */
129 NODE_T grandparent;
130 NODE_T uncle;
132 if (parent->color == BLACK)
134 /* A RED color for node is acceptable. */
135 node->color = RED;
136 return;
139 grandparent = parent->parent;
140 /* Since parent is RED, we know that
141 grandparent is != NULL and colored BLACK. */
143 if (grandparent->left == parent)
144 uncle = grandparent->right;
145 else if (grandparent->right == parent)
146 uncle = grandparent->left;
147 else
148 abort ();
150 if (uncle != NULL && uncle->color == RED)
152 /* Change grandparent from BLACK to RED, and
153 change parent and uncle from RED to BLACK.
154 This makes it acceptable for node to be RED. */
155 node->color = RED;
156 parent->color = uncle->color = BLACK;
157 node = grandparent;
159 else
161 /* grandparent and uncle are BLACK. parent is RED. node wants
162 to be RED too.
163 In this case, recoloring is not sufficient. Need to perform
164 one or two rotations. */
165 NODE_T *grandparentp;
167 if (grandparent->parent == NULL)
168 grandparentp = &container->root;
169 else if (grandparent->parent->left == grandparent)
170 grandparentp = &grandparent->parent->left;
171 else if (grandparent->parent->right == grandparent)
172 grandparentp = &grandparent->parent->right;
173 else
174 abort ();
176 if (grandparent->left == parent)
178 if (parent->right == node)
180 /* Rotation between node and parent. */
181 grandparent->left = rotate_left (parent, node);
182 node = parent;
183 parent = grandparent->left;
185 /* grandparent and uncle are BLACK. parent and node want to be
186 RED. parent = grandparent->left. node = parent->left.
188 grandparent parent
189 bh+1 bh+1
190 / \ / \
191 parent uncle --> node grandparent
192 bh bh bh bh
193 / \ / \
194 node C C uncle
195 bh bh bh bh
197 *grandparentp = rotate_right (parent, grandparent);
198 parent->color = BLACK;
199 node->color = grandparent->color = RED;
201 else /* grandparent->right == parent */
203 if (parent->left == node)
205 /* Rotation between node and parent. */
206 grandparent->right = rotate_right (node, parent);
207 node = parent;
208 parent = grandparent->right;
210 /* grandparent and uncle are BLACK. parent and node want to be
211 RED. parent = grandparent->right. node = parent->right.
213 grandparent parent
214 bh+1 bh+1
215 / \ / \
216 uncle parent --> grandparent node
217 bh bh bh bh
218 / \ / \
219 C node uncle C
220 bh bh bh bh
222 *grandparentp = rotate_left (grandparent, parent);
223 parent->color = BLACK;
224 node->color = grandparent->color = RED;
226 return;
229 /* Start again with a new (node, parent) pair. */
230 parent = node->parent;
232 if (parent == NULL)
234 /* Change node's color from RED to BLACK. This increases the
235 tree's black-height. */
236 node->color = BLACK;
237 return;
242 /* Ensure the tree is balanced, after a deletion operation.
243 CHILD was a grandchild of PARENT and is now its child. Between them,
244 a black node was removed. CHILD is also black, or NULL.
245 (CHILD can also be NULL. But PARENT is non-NULL.) */
246 static void
247 rebalance_after_remove (CONTAINER_T container, NODE_T child, NODE_T parent)
249 for (;;)
251 /* At this point, we reduced the black-height of the CHILD subtree by 1.
252 To make up, either look for a possibility to turn a RED to a BLACK
253 node, or try to reduce the black-height tree of CHILD's sibling
254 subtree as well. */
255 NODE_T *parentp;
257 if (parent->parent == NULL)
258 parentp = &container->root;
259 else if (parent->parent->left == parent)
260 parentp = &parent->parent->left;
261 else if (parent->parent->right == parent)
262 parentp = &parent->parent->right;
263 else
264 abort ();
266 if (parent->left == child)
268 NODE_T sibling = parent->right;
269 /* sibling's black-height is >= 1. In particular,
270 sibling != NULL.
272 parent
274 child sibling
275 bh bh+1
278 if (sibling->color == RED)
280 /* sibling is RED, hence parent is BLACK and sibling's children
281 are non-NULL and BLACK.
283 parent sibling
284 bh+2 bh+2
285 / \ / \
286 child sibling --> parent SR
287 bh bh+1 bh+1 bh+1
288 / \ / \
289 SL SR child SL
290 bh+1 bh+1 bh bh+1
292 *parentp = rotate_left (parent, sibling);
293 parent->color = RED;
294 sibling->color = BLACK;
296 /* Concentrate on the subtree of parent. The new sibling is
297 one of the old sibling's children, and known to be BLACK. */
298 parentp = &sibling->left;
299 sibling = parent->right;
301 /* Now we know that sibling is BLACK.
303 parent
305 child sibling
306 bh bh+1
308 if (sibling->right != NULL && sibling->right->color == RED)
311 parent sibling
312 bh+1|bh+2 bh+1|bh+2
313 / \ / \
314 child sibling --> parent SR
315 bh bh+1 bh+1 bh+1
316 / \ / \
317 SL SR child SL
318 bh bh bh bh
320 *parentp = rotate_left (parent, sibling);
321 sibling->color = parent->color;
322 parent->color = BLACK;
323 sibling->right->color = BLACK;
324 return;
326 else if (sibling->left != NULL && sibling->left->color == RED)
329 parent parent
330 bh+1|bh+2 bh+1|bh+2
331 / \ / \
332 child sibling --> child SL
333 bh bh+1 bh bh+1
334 / \ / \
335 SL SR SLL sibling
336 bh bh bh bh
337 / \ / \
338 SLL SLR SLR SR
339 bh bh bh bh
341 where SLL, SLR, SR are all black.
343 parent->right = rotate_right (sibling->left, sibling);
344 /* Change sibling from BLACK to RED and SL from RED to BLACK. */
345 sibling->color = RED;
346 sibling = parent->right;
347 sibling->color = BLACK;
349 /* Now do as in the previous case. */
350 *parentp = rotate_left (parent, sibling);
351 sibling->color = parent->color;
352 parent->color = BLACK;
353 sibling->right->color = BLACK;
354 return;
356 else
358 if (parent->color == BLACK)
360 /* Change sibling from BLACK to RED. Then the entire
361 subtree at parent has decreased its black-height.
362 parent parent
363 bh+2 bh+1
364 / \ / \
365 child sibling --> child sibling
366 bh bh+1 bh bh
368 sibling->color = RED;
370 child = parent;
372 else
374 /* Change parent from RED to BLACK, but compensate by
375 changing sibling from BLACK to RED.
376 parent parent
377 bh+1 bh+1
378 / \ / \
379 child sibling --> child sibling
380 bh bh+1 bh bh
382 parent->color = BLACK;
383 sibling->color = RED;
384 return;
388 else if (parent->right == child)
390 NODE_T sibling = parent->left;
391 /* sibling's black-height is >= 1. In particular,
392 sibling != NULL.
394 parent
396 sibling child
397 bh+1 bh
400 if (sibling->color == RED)
402 /* sibling is RED, hence parent is BLACK and sibling's children
403 are non-NULL and BLACK.
405 parent sibling
406 bh+2 bh+2
407 / \ / \
408 sibling child --> SR parent
409 bh+1 ch bh+1 bh+1
410 / \ / \
411 SL SR SL child
412 bh+1 bh+1 bh+1 bh
414 *parentp = rotate_right (sibling, parent);
415 parent->color = RED;
416 sibling->color = BLACK;
418 /* Concentrate on the subtree of parent. The new sibling is
419 one of the old sibling's children, and known to be BLACK. */
420 parentp = &sibling->right;
421 sibling = parent->left;
423 /* Now we know that sibling is BLACK.
425 parent
427 sibling child
428 bh+1 bh
430 if (sibling->left != NULL && sibling->left->color == RED)
433 parent sibling
434 bh+1|bh+2 bh+1|bh+2
435 / \ / \
436 sibling child --> SL parent
437 bh+1 bh bh+1 bh+1
438 / \ / \
439 SL SR SR child
440 bh bh bh bh
442 *parentp = rotate_right (sibling, parent);
443 sibling->color = parent->color;
444 parent->color = BLACK;
445 sibling->left->color = BLACK;
446 return;
448 else if (sibling->right != NULL && sibling->right->color == RED)
451 parent parent
452 bh+1|bh+2 bh+1|bh+2
453 / \ / \
454 sibling child --> SR child
455 bh+1 bh bh+1 bh
456 / \ / \
457 SL SR sibling SRR
458 bh bh bh bh
459 / \ / \
460 SRL SRR SL SRL
461 bh bh bh bh
463 where SL, SRL, SRR are all black.
465 parent->left = rotate_left (sibling, sibling->right);
466 /* Change sibling from BLACK to RED and SL from RED to BLACK. */
467 sibling->color = RED;
468 sibling = parent->left;
469 sibling->color = BLACK;
471 /* Now do as in the previous case. */
472 *parentp = rotate_right (sibling, parent);
473 sibling->color = parent->color;
474 parent->color = BLACK;
475 sibling->left->color = BLACK;
476 return;
478 else
480 if (parent->color == BLACK)
482 /* Change sibling from BLACK to RED. Then the entire
483 subtree at parent has decreased its black-height.
484 parent parent
485 bh+2 bh+1
486 / \ / \
487 sibling child --> sibling child
488 bh+1 bh bh bh
490 sibling->color = RED;
492 child = parent;
494 else
496 /* Change parent from RED to BLACK, but compensate by
497 changing sibling from BLACK to RED.
498 parent parent
499 bh+1 bh+1
500 / \ / \
501 sibling child --> sibling child
502 bh+1 bh bh bh
504 parent->color = BLACK;
505 sibling->color = RED;
506 return;
510 else
511 abort ();
513 /* Start again with a new (child, parent) pair. */
514 parent = child->parent;
516 #if 0 /* Already handled. */
517 if (child != NULL && child->color == RED)
519 child->color = BLACK;
520 return;
522 #endif
524 if (parent == NULL)
525 return;
529 static NODE_T
530 gl_tree_nx_add_first (CONTAINER_T container, NODE_PAYLOAD_PARAMS)
532 /* Create new node. */
533 NODE_T new_node =
534 (struct NODE_IMPL *) malloc (sizeof (struct NODE_IMPL));
536 if (new_node == NULL)
537 return NULL;
539 new_node->left = NULL;
540 new_node->right = NULL;
541 NODE_PAYLOAD_ASSIGN(new_node)
543 /* Add it to the tree. */
544 if (container->root == NULL)
546 new_node->color = BLACK;
547 container->root = new_node;
548 new_node->parent = NULL;
550 else
552 NODE_T node;
554 for (node = container->root; node->left != NULL; )
555 node = node->left;
557 node->left = new_node;
558 new_node->parent = node;
560 /* Color and rebalance. */
561 rebalance_after_add (container, new_node, node);
564 container->count++;
565 return new_node;
568 static NODE_T
569 gl_tree_nx_add_before (CONTAINER_T container, NODE_T node, NODE_PAYLOAD_PARAMS)
571 /* Create new node. */
572 NODE_T new_node =
573 (struct NODE_IMPL *) malloc (sizeof (struct NODE_IMPL));
575 if (new_node == NULL)
576 return NULL;
578 new_node->left = NULL;
579 new_node->right = NULL;
580 NODE_PAYLOAD_ASSIGN(new_node)
582 /* Add it to the tree. */
583 if (node->left == NULL)
584 node->left = new_node;
585 else
587 for (node = node->left; node->right != NULL; )
588 node = node->right;
589 node->right = new_node;
591 new_node->parent = node;
593 /* Color and rebalance. */
594 rebalance_after_add (container, new_node, node);
596 container->count++;
597 return new_node;
600 static NODE_T
601 gl_tree_nx_add_after (CONTAINER_T container, NODE_T node, NODE_PAYLOAD_PARAMS)
603 /* Create new node. */
604 NODE_T new_node =
605 (struct NODE_IMPL *) malloc (sizeof (struct NODE_IMPL));
607 if (new_node == NULL)
608 return NULL;
610 new_node->left = NULL;
611 new_node->right = NULL;
612 NODE_PAYLOAD_ASSIGN(new_node)
614 /* Add it to the tree. */
615 if (node->right == NULL)
616 node->right = new_node;
617 else
619 for (node = node->right; node->left != NULL; )
620 node = node->left;
621 node->left = new_node;
623 new_node->parent = node;
625 /* Color and rebalance. */
626 rebalance_after_add (container, new_node, node);
628 container->count++;
629 return new_node;
632 static bool
633 gl_tree_remove_node (CONTAINER_T container, NODE_T node)
635 NODE_T parent = node->parent;
637 if (node->left == NULL)
639 /* Replace node with node->right. */
640 NODE_T child = node->right;
642 if (child != NULL)
644 child->parent = parent;
645 /* Since node->left == NULL, child must be RED and of height 1,
646 hence node must have been BLACK. Recolor the child. */
647 child->color = BLACK;
649 if (parent == NULL)
650 container->root = child;
651 else
653 if (parent->left == node)
654 parent->left = child;
655 else /* parent->right == node */
656 parent->right = child;
658 if (child == NULL && node->color == BLACK)
659 rebalance_after_remove (container, child, parent);
662 else if (node->right == NULL)
664 /* It is not absolutely necessary to treat this case. But the more
665 general case below is more complicated, hence slower. */
666 /* Replace node with node->left. */
667 NODE_T child = node->left;
669 child->parent = parent;
670 /* Since node->right == NULL, child must be RED and of height 1,
671 hence node must have been BLACK. Recolor the child. */
672 child->color = BLACK;
673 if (parent == NULL)
674 container->root = child;
675 else
677 if (parent->left == node)
678 parent->left = child;
679 else /* parent->right == node */
680 parent->right = child;
683 else
685 /* Replace node with the rightmost element of the node->left subtree. */
686 NODE_T subst;
687 NODE_T subst_parent;
688 NODE_T child;
689 color_t removed_color;
691 for (subst = node->left; subst->right != NULL; )
692 subst = subst->right;
694 subst_parent = subst->parent;
696 child = subst->left;
698 removed_color = subst->color;
700 /* The case subst_parent == node is special: If we do nothing special,
701 we get confusion about node->left, subst->left and child->parent.
702 subst_parent == node
703 <==> The 'for' loop above terminated immediately.
704 <==> subst == subst_parent->left
705 [otherwise subst == subst_parent->right]
706 In this case, we would need to first set
707 child->parent = node; node->left = child;
708 and later - when we copy subst into node's position - again
709 child->parent = subst; subst->left = child;
710 Altogether a no-op. */
711 if (subst_parent != node)
713 if (child != NULL)
714 child->parent = subst_parent;
715 subst_parent->right = child;
718 /* Copy subst into node's position.
719 (This is safer than to copy subst's value into node, keep node in
720 place, and free subst.) */
721 if (subst_parent != node)
723 subst->left = node->left;
724 subst->left->parent = subst;
726 subst->right = node->right;
727 subst->right->parent = subst;
728 subst->color = node->color;
729 subst->parent = parent;
730 if (parent == NULL)
731 container->root = subst;
732 else if (parent->left == node)
733 parent->left = subst;
734 else /* parent->right == node */
735 parent->right = subst;
737 if (removed_color == BLACK)
739 if (child != NULL && child->color == RED)
740 /* Recolor the child. */
741 child->color = BLACK;
742 else
743 /* Rebalancing starts at child's parent, that is subst_parent -
744 except when subst_parent == node. In this case, we need to use
745 its replacement, subst. */
746 rebalance_after_remove (container, child,
747 subst_parent != node ? subst_parent : subst);
751 container->count--;
752 NODE_PAYLOAD_DISPOSE
753 free (node);
754 return true;
757 /* For debugging. */
758 static unsigned int
759 check_invariants (NODE_T node, NODE_T parent, size_t *counterp)
761 unsigned int left_blackheight =
762 (node->left != NULL ? check_invariants (node->left, node, counterp) : 0);
763 unsigned int right_blackheight =
764 (node->right != NULL ? check_invariants (node->right, node, counterp) : 0);
766 if (!(node->parent == parent))
767 abort ();
768 if (!(node->color == BLACK || node->color == RED))
769 abort ();
770 if (parent == NULL && !(node->color == BLACK))
771 abort ();
772 if (!(left_blackheight == right_blackheight))
773 abort ();
775 (*counterp)++;
777 return left_blackheight + (node->color == BLACK ? 1 : 0);