support constructing a version object with a string argument
[liba.git] / src / avl.c
blobaa0b53fdc9e12d0544dd764b78c3bbef82aea7dc
1 #include "a/avl.h"
3 /* Replaces the child of the specified AVL tree node. */
4 static A_INLINE void a_avl_new_child(a_avl *root, a_avl_node *parent, a_avl_node *node, a_avl_node *newnode)
6 if (parent)
8 if (parent->left == node)
10 parent->left = newnode;
12 else
14 parent->right = newnode;
17 else
19 root->node = newnode;
23 /* Returns the child of the specified AVL tree node. */
24 static A_INLINE a_avl_node *a_avl_child(a_avl_node const *node, int sign)
26 return sign < 0 ? node->left : node->right;
29 /* Sets the child of the specified AVL tree node. */
30 static A_INLINE void a_avl_set_child(a_avl_node *node, a_avl_node *child, int sign)
32 *(sign < 0 ? &node->left : &node->right) = child;
35 /* Sets the parent and balance factor of the specified AVL tree node. */
36 static A_INLINE void a_avl_set_parent_factor(a_avl_node *node, a_avl_node *parent, int factor)
38 #if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
39 node->_parent = (a_uptr)parent | (a_uptr)(factor + 1);
40 #else /* !A_SIZE_POINTER */
41 node->parent = parent;
42 node->factor = factor;
43 #endif /* A_SIZE_POINTER */
46 /* Sets the parent of the specified AVL tree node. */
47 static A_INLINE void a_avl_set_parent(a_avl_node *node, a_avl_node *parent)
49 #if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
50 node->_parent = (a_uptr)parent | (node->_parent & 3);
51 #else /* !A_SIZE_POINTER */
52 node->parent = parent;
53 #endif /* A_SIZE_POINTER */
57 Returns the balance factor of the specified AVL tree node --- that is,
58 the height of its right subtree minus the height of its left subtree.
60 static A_INLINE int a_avl_factor(a_avl_node const *node)
62 #if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
63 return (int)(node->_parent & 3) - 1;
64 #else /* !A_SIZE_POINTER */
65 return node->factor;
66 #endif /* A_SIZE_POINTER */
70 Adds $amount to the balance factor of the specified AVL tree node.
71 The caller must ensure this still results in a valid balance factor (-1, 0, or 1).
73 static A_INLINE void a_avl_set_factor(a_avl_node *node, int amount)
75 #if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
76 node->_parent += (a_uptr)amount;
77 #else /* !A_SIZE_POINTER */
78 node->factor += amount;
79 #endif /* A_SIZE_POINTER */
83 Template for performing a single rotation (nodes marked with ? may not exist)
85 sign > 0: Rotate clockwise (right) rooted at A:
87 P? P?
88 | |
89 A B
90 / \ / \
91 B C? => D? A
92 / \ / \
93 D? E? E? C?
95 sign < 0: Rotate counterclockwise (left) rooted at A:
97 P? P?
98 | |
99 A B
100 / \ / \
101 C? B => A D?
102 / \ / \
103 E? D? C? E?
105 This updates pointers but not balance factors!
107 static A_INLINE void a_avl_rotate(a_avl *root, a_avl_node *A, int sign)
109 a_avl_node *const P = a_avl_parent(A);
110 a_avl_node *const B = a_avl_child(A, -sign);
111 a_avl_node *const E = a_avl_child(B, +sign);
113 a_avl_set_child(A, E, -sign);
114 a_avl_set_parent(A, B);
116 a_avl_set_child(B, A, +sign);
117 a_avl_set_parent(B, P);
119 if (E) { a_avl_set_parent(E, A); }
120 a_avl_new_child(root, P, A, B);
124 Template for performing a double rotation (nodes marked with ? may not exist)
126 sign > 0: Rotate counterclockwise (left) rooted at B, then clockwise (right) rooted at A:
128 P? P? P?
129 | | |
130 A A E
131 / \ / \ / \
132 B C? => E C? => B A
133 / \ / \ / \ / \
134 D? E B G? D? F?G? C?
135 / \ / \
136 F? G? D? F?
138 sign < 0: Rotate clockwise (right) rooted at B, then counterclockwise (left) rooted at A:
140 P? P? P?
141 | | |
142 A A E
143 / \ / \ / \
144 C? B => C? E => A B
145 / \ / \ / \ / \
146 E D? G? B C? G?F? D?
147 / \ / \
148 G? F? F? D?
150 Returns a pointer to E and updates balance factors. Except for those two things, this function is equivalent to:
152 a_avl_rotate(root, B, -sign);
153 a_avl_rotate(root, A, +sign);
155 static A_INLINE a_avl_node *a_avl_rotate2(a_avl *root, a_avl_node *B, a_avl_node *A, int sign)
157 a_avl_node *const P = a_avl_parent(A);
158 a_avl_node *const E = a_avl_child(B, +sign);
159 a_avl_node *const F = a_avl_child(E, -sign);
160 a_avl_node *const G = a_avl_child(E, +sign);
161 int const e = a_avl_factor(E);
163 a_avl_set_child(A, G, -sign);
164 a_avl_set_parent_factor(A, E, (sign * e >= 0) ? 0 : -e);
166 a_avl_set_child(B, F, +sign);
167 a_avl_set_parent_factor(B, E, (sign * e <= 0) ? 0 : -e);
169 a_avl_set_child(E, A, +sign);
170 a_avl_set_child(E, B, -sign);
171 a_avl_set_parent_factor(E, P, 0);
173 if (F) { a_avl_set_parent(F, B); }
174 if (G) { a_avl_set_parent(G, A); }
175 a_avl_new_child(root, P, A, E);
177 return E;
181 This function handles the growth of a subtree due to an insertion.
183 root
184 Location of the tree's root pointer.
186 node
187 A subtree that has increased in height by 1 due to an insertion.
189 parent
190 Parent of node; must not be null.
192 sign
193 -1 if node is the left child of parent;
194 +1 if node is the right child of parent.
196 This function will adjust parent's balance factor, then do a (single or double) rotation if necessary.
197 The return value will be $true if the full AVL tree is now adequately balanced,
198 or $false if the subtree rooted at parent is now adequately balanced but has increased in height by 1,
199 so the caller should continue up the tree.
201 Note that if $false is returned, no rotation will have been done.
202 Indeed, a single node insertion cannot require that more than one (single or double) rotation be done.
204 static A_INLINE a_bool a_avl_handle_growth(a_avl *root, a_avl_node *parent, a_avl_node *node, int sign)
206 int const cur_factor = a_avl_factor(parent);
207 if (cur_factor == 0)
209 /* $parent is still sufficiently balanced (-1 or +1 balance factor), but must have increased in height. Continue up the tree. */
210 a_avl_set_factor(parent, sign);
211 return A_FALSE;
214 int const new_factor = cur_factor + sign;
215 if (new_factor == 0)
217 /* $parent is now perfectly balanced (0 balance factor). It cannot have increased in height, so there is nothing more to do. */
218 a_avl_set_factor(parent, sign);
219 return A_TRUE;
222 /* $parent is too left-heavy (new_balance_factor == -2) or too right-heavy (new_balance_factor == +2). */
225 Test whether $node is left-heavy (-1 balance factor) or right-heavy (+1 balance factor).
226 Note that it cannot be perfectly balanced (0 balance factor) because here we are under the invariant that
227 $node has increased in height due to the insertion.
229 if (sign * a_avl_factor(node) > 0)
232 $node (B below) is heavy in the same direction $parent (A below) is heavy.
233 The comment, diagram, and equations below assume sign < 0. The other case is symmetric!
234 Do a clockwise rotation rooted at $parent (A below):
237 / \ / \
238 B C? => D A
239 / \ / \ / \
240 D E? F? G?E? C?
242 F? G?
244 Before the rotation:
245 balance(A) = -2
246 balance(B) = -1
247 Let x = height(C). Then:
248 height(B) = x + 2
249 height(D) = x + 1
250 height(E) = x
251 max(height(F), height(G)) = x.
253 After the rotation:
254 height(D) = max(height(F), height(G)) + 1
255 = x + 1
256 height(A) = max(height(E), height(C)) + 1
257 = max(x, x) + 1 = x + 1
258 balance(B) = 0
259 balance(A) = 0
261 a_avl_rotate(root, parent, -sign);
263 /* Equivalent to setting $parent's balance factor to 0. */
264 a_avl_set_factor(parent, -sign); // A
266 /* Equivalent to setting $node's balance factor to 0. */
267 a_avl_set_factor(node, -sign); // B
269 else
272 $node (B below) is heavy in the direction opposite from the direction $parent (A below) is heavy.
273 The comment, diagram, and equations below assume sign < 0. The other case is symmetric!
274 Do a counterblockwise rotation rooted at $node (B below), then a clockwise rotation rooted at $parent (A below):
276 A A E
277 / \ / \ / \
278 B C? => E C? => B A
279 / \ / \ / \ / \
280 D? E B G? D? F?G? C?
281 / \ / \
282 F? G? D? F?
284 Before the rotation:
285 balance(A) = -2
286 balance(B) = +1
287 Let x = height(C). Then:
288 height(B) = x + 2
289 height(E) = x + 1
290 height(D) = x
291 max(height(F), height(G)) = x
293 After both rotations:
294 height(A) = max(height(G), height(C)) + 1
295 = x + 1
296 balance(A) = balance(E{orig}) >= 0 ? 0 : -balance(E{orig})
297 height(B) = max(height(D), height(F)) + 1
298 = x + 1
299 balance(B) = balance(E{orig} <= 0) ? 0 : -balance(E{orig})
301 height(E) = x + 2
302 balance(E) = 0
304 a_avl_rotate2(root, node, parent, -sign);
307 /* Height after rotation is unchanged; nothing more to do. */
308 return A_TRUE;
311 void a_avl_insert_adjust(a_avl *root, a_avl_node *node)
313 /* Adjust balance factor of new node's parent. No rotation will need to be done at this level. */
315 a_avl_node *parent = a_avl_parent(node);
316 if (!parent) { return; }
318 if (parent->left == node)
320 a_avl_set_factor(parent, -1);
322 else
324 a_avl_set_factor(parent, +1);
327 /* $parent did not change in height. Nothing more to do. */
328 if (a_avl_factor(parent) == 0) { return; }
330 /* The subtree rooted at parent increased in height by 1. */
332 a_bool done;
333 do {
334 node = parent;
335 parent = a_avl_parent(node);
336 if (!parent) { return; }
337 if (parent->left == node)
339 done = a_avl_handle_growth(root, parent, node, -1);
341 else
343 done = a_avl_handle_growth(root, parent, node, +1);
345 } while (!done);
349 This function handles the shrinkage of a subtree due to a deletion.
351 root
352 Location of the tree's root pointer.
354 parent
355 A node in the tree, exactly one of whose subtrees has decreased in height by 1 due to a deletion.
356 (This includes the case where one of the child pointers has become null,
357 since we can consider the "null" subtree to have a height of 0.)
359 sign
360 +1 if the left subtree of parent has decreased in height by 1;
361 -1 if the right subtree of parent has decreased in height by 1.
363 left
364 If the return value is not null, this will be set to
365 $true if the left subtree of the returned node has decreased in height by 1,
366 $false if the right subtree of the returned node has decreased in height by 1.
368 This function will adjust parent's balance factor, then do a (single or double) rotation if necessary.
369 The return value will be null if the full AVL tree is now adequately balanced,
370 or a pointer to the parent of parent if parent is now adequately balanced but has decreased in height by 1.
371 Also in the latter case, *left will be set.
373 static A_INLINE a_avl_node *a_avl_handle_shrink(a_avl *root, a_avl_node *parent, int sign, a_bool *left)
375 int const cur_factor = a_avl_factor(parent);
376 if (cur_factor == 0)
379 Prior to the deletion, the subtree rooted at $parent was perfectly balanced.
380 It's now unbalanced by 1, but that's okay and its height hasn't changed. Nothing more to do.
382 a_avl_set_factor(parent, sign);
383 return A_NULL;
386 a_avl_node *node;
387 int const new_factor = cur_factor + sign;
388 if (new_factor == 0)
391 The subtree rooted at $parent is now perfectly balanced, whereas before the deletion it was unbalanced by 1.
392 Its height must have decreased by 1. No rotation is needed at this location, but continue up the tree.
394 a_avl_set_factor(parent, sign);
395 node = parent;
397 else
399 /* $parent is too left-heavy (new_factor == -2) or too right-heavy (new_factor == +2). */
400 node = a_avl_child(parent, sign);
403 The rotations below are similar to those done during insertion, so full comments are not provided.
404 The only new case is the one where $node has a balance factor of 0, and that is commented.
406 if (sign * a_avl_factor(node) >= 0)
408 a_avl_rotate(root, parent, -sign);
409 if (a_avl_factor(node) == 0)
412 $node (B below) is perfectly balanced.
413 The comment, diagram, and equations below assume sign < 0. The other case is symmetric!
414 Do a clockwise rotation rooted at $parent (A below):
417 / \ / \
418 B C? => D A
419 / \ / \ / \
420 D E F? G?E C?
422 F? G?
424 Before the rotation:
425 balance(A) = -2
426 balance(B) = 0
427 Let x = height(C). Then:
428 height(B) = x + 2
429 height(D) = x + 1
430 height(E) = x + 1
431 max(height(F), height(G)) = x.
433 After the rotation:
434 height(D) = max(height(F), height(G)) + 1
435 = x + 1
436 height(A) = max(height(E), height(C)) + 1
437 = max(x + 1, x) + 1 = x + 2
438 balance(A) = -1
439 balance(B) = +1
441 A: -2 => -1 (sign < 0) or +2 => +1 (sign > 0)
442 No change needed --- that's the same as cur_factor.
444 B: 0 => +1 (sign < 0) or 0 => -1 (sign > 0)
446 a_avl_set_factor(node, -sign);
448 /* Height is unchanged; nothing more to do. */
449 return A_NULL;
451 else
453 a_avl_set_factor(parent, -sign);
454 a_avl_set_factor(node, -sign);
457 else
459 node = a_avl_rotate2(root, node, parent, -sign);
462 parent = a_avl_parent(node);
463 if (parent) { *left = (parent->left == node); }
464 return parent;
468 Swaps node X, which must have 2 children, with its in-order successor, then unlinks node X.
469 Returns the parent of X just before unlinking, without its balance factor having been updated to account for the unlink.
471 static A_INLINE a_avl_node *a_avl_handle_remove(a_avl *root, a_avl_node *X, a_bool *left)
473 a_avl_node *node;
475 a_avl_node *Y = X->right;
476 if (!Y->left)
479 P? P? P?
480 | | |
481 X Y Y
482 / \ / \ / \
483 A Y => A X => A B?
484 / \ / \
485 (0) B? (0) B?
487 [ X unlinked, Y returned ]
489 *left = A_FALSE;
490 node = Y;
492 else
494 a_avl_node *Q;
495 do {
496 Q = Y;
497 Y = Y->left;
498 } while (Y->left);
500 P? P? P?
501 | | |
502 X Y Y
503 / \ / \ / \
504 A ... => A ... => A ...
505 | | |
506 Q Q Q
507 / / /
508 Y X B?
509 / \ / \
510 (0) B? (0) B?
512 [ X unlinked, Q returned ]
514 Q->left = Y->right;
515 if (Y->right)
517 a_avl_set_parent(Y->right, Q);
519 Y->right = X->right;
520 a_avl_set_parent(X->right, Y);
521 *left = A_TRUE;
522 node = Q;
525 Y->left = X->left;
526 a_avl_set_parent(X->left, Y);
528 #if defined(A_SIZE_POINTER) && (A_SIZE_POINTER + 0 > 3)
529 Y->_parent = X->_parent;
530 #else /* !A_SIZE_POINTER */
531 Y->parent = X->parent;
532 Y->factor = X->factor;
533 #endif /* A_SIZE_POINTER */
534 a_avl_new_child(root, a_avl_parent(X), X, Y);
536 return node;
539 void a_avl_remove(a_avl *root, a_avl_node *node)
541 a_avl_node *parent;
542 a_bool left = A_FALSE;
543 if (node->left && node->right)
546 $node is fully internal, with two children. Swap it with its in-order successor
547 (which must exist in the right subtree of $node and can have, at most, a right child),
548 then unlink $node.
550 parent = a_avl_handle_remove(root, node, &left);
552 $parent is now the parent of what was $node's in-order successor.
553 It cannot be null, since $node itself was an ancestor of its in-order successor.
554 $left has been set to $true if $node's in-order successor was the left child of $parent, otherwise $false.
557 else
559 a_avl_node *const child = node->left ? node->left : node->right;
561 $node is missing at least one child. Unlink it. Set $parent to $node's parent,
562 and set $left to reflect which child of $parent $node was.
563 Or, if $node was the root node, simply update the root node and return.
565 parent = a_avl_parent(node);
566 if (parent)
568 if (parent->left == node)
570 parent->left = child;
571 left = A_TRUE;
573 else
575 parent->right = child;
576 left = A_FALSE;
578 if (child) { a_avl_set_parent(child, parent); }
580 else
582 if (child) { a_avl_set_parent(child, parent); }
583 root->node = child;
584 return;
587 /* Rebalance the tree. */
590 if (left)
592 parent = a_avl_handle_shrink(root, parent, +1, &left);
594 else
596 parent = a_avl_handle_shrink(root, parent, -1, &left);
598 } while (parent);
601 a_avl_node *a_avl_insert(a_avl *root, a_avl_node *node, int (*cmp)(void const *, void const *))
603 a_avl_node *parent = root->node;
604 a_avl_node **link = &root->node;
605 while (*link)
607 parent = *link;
608 int const res = cmp(node, parent);
609 if (res < 0)
611 link = &parent->left;
613 else if (res > 0)
615 link = &parent->right;
617 else { return parent; }
619 *link = a_avl_init(node, parent);
620 a_avl_insert_adjust(root, node);
621 return A_NULL;
624 a_avl_node *a_avl_search(a_avl const *root, void const *ctx, int (*cmp)(void const *, void const *))
626 for (a_avl_node *cur = root->node; cur;)
628 int const res = cmp(ctx, cur);
629 if (res < 0)
631 cur = cur->left;
633 else if (res > 0)
635 cur = cur->right;
637 else { return cur; }
639 return A_NULL;
642 a_avl_node *a_avl_head(a_avl const *root)
644 a_avl_node *node = root->node;
645 if (node)
647 while (node->left) { node = node->left; }
649 return node;
652 a_avl_node *a_avl_tail(a_avl const *root)
654 a_avl_node *node = root->node;
655 if (node)
657 while (node->right) { node = node->right; }
659 return node;
662 a_avl_node *a_avl_next(a_avl_node *node)
668 / \ / \
669 A C E G
671 if (!node) { return node; }
672 if (node->right) /* D -> F -> E */
674 for (node = node->right; node->left; node = node->left) {}
676 else /* C -> B -> D */
678 a_avl_node *last = node;
679 for (node = a_avl_parent(node); node && node->left != last;)
681 last = node;
682 node = a_avl_parent(node);
685 return node;
688 a_avl_node *a_avl_prev(a_avl_node *node)
690 if (!node) { return node; }
691 if (node->left)
693 for (node = node->left; node->right; node = node->right) {}
695 else
697 a_avl_node *last = node;
698 for (node = a_avl_parent(node); node && node->right != last;)
700 last = node;
701 node = a_avl_parent(node);
704 return node;
707 a_avl_node *a_avl_pre_next(a_avl_node *node)
713 / \ / \
714 A C E G
716 a_avl_node *last = node;
717 if (!node) { return node; }
718 if (node->left) { return node->left; }
719 if (node->right) { return node->right; }
720 for (node = a_avl_parent(node); node; node = a_avl_parent(node))
722 if (node->right && node->right != last)
724 node = node->right; /* A -> B -> C */
725 break;
727 last = node; /* C -> B -> D -> F */
729 return node;
732 a_avl_node *a_avl_pre_prev(a_avl_node *node)
734 a_avl_node *last = node;
735 if (!node) { return node; }
736 if (node->right) { return node->right; }
737 if (node->left) { return node->left; }
738 for (node = a_avl_parent(node); node; node = a_avl_parent(node))
740 if (node->left && node->left != last)
742 node = node->left;
743 break;
745 last = node;
747 return node;
750 #define A_AVL_POST(head, tail) \
751 for (;;) \
753 if (node->head) \
755 node = node->head; \
757 else if (node->tail) \
759 node = node->tail; \
761 else { break; } \
763 (void)0
765 a_avl_node *a_avl_post_head(a_avl const *root)
767 a_avl_node *node = root->node;
768 if (node) { A_AVL_POST(left, right); }
769 return node;
772 a_avl_node *a_avl_post_tail(a_avl const *root)
774 a_avl_node *node = root->node;
775 if (node) { A_AVL_POST(right, left); }
776 return node;
779 a_avl_node *a_avl_post_next(a_avl_node *node)
785 / \ / \
786 A C E G
788 a_avl_node *last = node;
789 if (!node) { return node; }
790 node = a_avl_parent(node);
791 if (node && node->right && node->right != last)
793 node = node->right; /* B -> D -> F -> E */
794 A_AVL_POST(left, right); /* A -> B -> C */
795 } /* C -> B */
796 return node;
799 a_avl_node *a_avl_post_prev(a_avl_node *node)
801 a_avl_node *last = node;
802 if (!node) { return node; }
803 node = a_avl_parent(node);
804 if (node && node->left && node->left != last)
806 node = node->left;
807 A_AVL_POST(right, left);
809 return node;
812 a_avl_node *a_avl_tear(a_avl *root, a_avl_node **next)
814 a_avl_node *node = *next;
815 if (!node)
817 node = root->node;
818 if (!node) { return node; }
820 A_AVL_POST(left, right);
821 *next = a_avl_parent(node);
822 a_avl_new_child(root, *next, node, A_NULL);
823 return node;