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
)
8 if (parent
->left
== node
)
10 parent
->left
= newnode
;
14 parent
->right
= 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 */
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:
95 sign < 0: Rotate counterclockwise (left) rooted at A:
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:
138 sign < 0: Rotate clockwise (right) rooted at B, then counterclockwise (left) rooted at A:
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
);
181 This function handles the growth of a subtree due to an insertion.
184 Location of the tree's root pointer.
187 A subtree that has increased in height by 1 due to an insertion.
190 Parent of node; must not be null.
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
);
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
);
214 int const new_factor
= cur_factor
+ sign
;
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
);
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):
247 Let x = height(C). Then:
251 max(height(F), height(G)) = x.
254 height(D) = max(height(F), height(G)) + 1
256 height(A) = max(height(E), height(C)) + 1
257 = max(x, x) + 1 = x + 1
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
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):
287 Let x = height(C). Then:
291 max(height(F), height(G)) = x
293 After both rotations:
294 height(A) = max(height(G), height(C)) + 1
296 balance(A) = balance(E{orig}) >= 0 ? 0 : -balance(E{orig})
297 height(B) = max(height(D), height(F)) + 1
299 balance(B) = balance(E{orig} <= 0) ? 0 : -balance(E{orig})
304 a_avl_rotate2(root
, node
, parent
, -sign
);
307 /* Height after rotation is unchanged; nothing more to do. */
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);
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. */
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);
343 done
= a_avl_handle_growth(root
, parent
, node
, +1);
349 This function handles the shrinkage of a subtree due to a deletion.
352 Location of the tree's root pointer.
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.)
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.
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
);
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
);
387 int const new_factor
= cur_factor
+ sign
;
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
);
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):
427 Let x = height(C). Then:
431 max(height(F), height(G)) = x.
434 height(D) = max(height(F), height(G)) + 1
436 height(A) = max(height(E), height(C)) + 1
437 = max(x + 1, x) + 1 = x + 2
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. */
453 a_avl_set_factor(parent
, -sign
);
454 a_avl_set_factor(node
, -sign
);
459 node
= a_avl_rotate2(root
, node
, parent
, -sign
);
462 parent
= a_avl_parent(node
);
463 if (parent
) { *left
= (parent
->left
== node
); }
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
)
475 a_avl_node
*Y
= X
->right
;
487 [ X unlinked, Y returned ]
504 A ... => A ... => A ...
512 [ X unlinked, Q returned ]
517 a_avl_set_parent(Y
->right
, Q
);
520 a_avl_set_parent(X
->right
, Y
);
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
);
539 void a_avl_remove(a_avl
*root
, a_avl_node
*node
)
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),
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.
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
);
568 if (parent
->left
== node
)
570 parent
->left
= child
;
575 parent
->right
= child
;
578 if (child
) { a_avl_set_parent(child
, parent
); }
582 if (child
) { a_avl_set_parent(child
, parent
); }
587 /* Rebalance the tree. */
592 parent
= a_avl_handle_shrink(root
, parent
, +1, &left
);
596 parent
= a_avl_handle_shrink(root
, parent
, -1, &left
);
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
;
608 int const res
= cmp(node
, parent
);
611 link
= &parent
->left
;
615 link
= &parent
->right
;
617 else { return parent
; }
619 *link
= a_avl_init(node
, parent
);
620 a_avl_insert_adjust(root
, node
);
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
);
642 a_avl_node
*a_avl_head(a_avl
const *root
)
644 a_avl_node
*node
= root
->node
;
647 while (node
->left
) { node
= node
->left
; }
652 a_avl_node
*a_avl_tail(a_avl
const *root
)
654 a_avl_node
*node
= root
->node
;
657 while (node
->right
) { node
= node
->right
; }
662 a_avl_node
*a_avl_next(a_avl_node
*node
)
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
;)
682 node
= a_avl_parent(node
);
688 a_avl_node
*a_avl_prev(a_avl_node
*node
)
690 if (!node
) { return node
; }
693 for (node
= node
->left
; node
->right
; node
= node
->right
) {}
697 a_avl_node
*last
= node
;
698 for (node
= a_avl_parent(node
); node
&& node
->right
!= last
;)
701 node
= a_avl_parent(node
);
707 a_avl_node
*a_avl_pre_next(a_avl_node
*node
)
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 */
727 last
= node
; /* C -> B -> D -> F */
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
)
750 #define A_AVL_POST(head, tail) \
757 else if (node->tail) \
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
); }
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
); }
779 a_avl_node
*a_avl_post_next(a_avl_node
*node
)
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 */
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
)
807 A_AVL_POST(right
, left
);
812 a_avl_node
*a_avl_tear(a_avl
*root
, a_avl_node
**next
)
814 a_avl_node
*node
= *next
;
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
);