chiark / gitweb /
@@@ tweak
[xyla] / avl.h
1 /* -*-c-*-
2  *
3  * AVL trees
4  *
5  * (c) 2024 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Xyla, a library of binary trees.
11  *
12  * Xyla is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the
14  * Free Software Foundation; either version 3 of the License, or (at your
15  * option) any later version.
16  *
17  * Xyla is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with Xyla.  If not, see <https://www.gnu.org/licenses/>.
24  */
25
26 #ifndef XYLA_AVL_H
27 #define XYLA_AVL_H
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "bt.h"
32
33 /*----- Data structures ---------------------------------------------------*/
34
35 struct xyla_avl_nodeslots {
36   unsigned f;
37 #define XYLA_AVLF_BALMASK 3u
38 #define XYLA_AVLBAL_LBIAS 1u
39 #define XYLA_AVLBAL_EVEN 0u
40 #define XYLA_AVLBAL_RBIAS 2u
41 };
42 #define XYLA_AVL_NODEPFX XYLA_BT_NODEPFX; struct xyla_avl_nodeslots avl
43 struct xyla_avl_node { XYLA_AVL_NODEPFX; };
44 #define XYLA_AVL_NODEUSFX struct xyla_avl_node avl; XYLA_BT_NODEUSFX
45 union xyla_avl_nodeu { XYLA_AVL_NODEUSFX; };
46
47 /* The maximum possible height H_n for an AVL tree containing n nodes is
48  * somewhat annoying to calculate.  The best way to start is to reverse the
49  * question and find the smallest number N_h of nodes which can force the
50  * tree to have height h.
51  *
52  * This is going to involve a recurrence.  The base case is the rather
53  * unsurprising observations that N_0 = 0 and N_1 = 1.
54  *
55  * The imbalance between the root's left and right subtrees can be at most 1.
56  * The cheapest way we can make a tree with height h, then, is if the root is
57  * biased to the left (say) and then its left and right subtrees are the
58  * smallest trees with height h - 1 and h - 2 respectively.  We have the
59  * oddly familiar recurrence
60  *
61  *      N_h = N_{h-1} + N_{h-2} + 1 .
62  *
63  * Guess that N_h = x^h + C for some constants x and C.  Then
64  *
65  *      x^h + C = x^{h-1} + x^{h-2} + 2 C + 1 ,
66  *
67  * and
68  *
69  *      x^h = x^{h-1} + x^{h-2} + C + 1 ,
70  *
71  * so setting C = -1 seems like the best bet; that leaves
72  *
73  *      x^h = x^{h-1} + x^{h-2} ,
74  *
75  * which is well-known to be solved by setting x = φ or x = φ̄, where
76  *
77  *          1 + √5                1 - √5
78  *      φ = ------     and     φ̄ = ------ .
79  *             2                       2
80  *
81  * This relationship clearly holds for any linear combination of φ and φ̄.  So
82  * we finally set
83  *
84  *      N_h = A φ^h + B φ̄^h - 1
85  *
86  * and check the initial conditions: N_0 = 0 forces A + B = 1; and N_1 = 1
87  * means
88  *
89  *      A φ + B φ̄ = 2 ;
90  *
91  * substituting φ and φ̄ and rearranging gives
92  *
93  *      (A + B) + √5 (A - B) = 4 .
94  *
95  * We know A + B = 1, so A - B = 3/√5 = 3 √5/5.  Adding these two gives
96  *
97  *          5 + 3 √5              5 - 3 √5
98  *      A = --------    and     B = -------- .
99  *             10                      10
100  *
101  * What we actually wanted to know was the maximum possible height H_n for an
102  * AVL tree with n nodes.  Suppose, then, that, for some h, the tree has
103  * n >= N_h >= A φ^h + B φ̄^h - 1 nodes.  Notice that |B < 1 and |φ̄| < 1;
104  * therefore, |B φ̄^h| < 1, and we have n >= A φ^h - 2.  (Sadly, φ̄ is
105  * negative.)
106  *
107  * Continuing, we see A φ^h <= n + 2.  Taking (binary) logs gives h lg φ +
108  * lg A <= lg (n + 2), whence
109  *
110  *           lg (n + 2) - lg A
111  *      h <= ----------------- .
112  *                  lg φ
113  *
114  * This is pretty gnarly to evaluate with the C preprocessor.  Fortunately,
115  * 0 < 13/9 - 1/lg φ < 1/200, so
116  *
117  *           13              lg A
118  *      h <= -- lg (n + 2) - ---- .
119  *            9              lg φ
120  *
121  * In fact, we can do better.  As n gets larger, the difference lg (n + 2) -
122  * lg n tends to zero.  There is therefore a value N such that
123  *
124  *      13         lg (n + 2) - lg A
125  *      -- lg n <= -----------------
126  *       9                lg φ
127  *
128  * whenever n >= N.
129  *
130  * This is too horrid to solve by hand, but numerical methods show that
131  * N = 12 satisfies our requirements.  We must, of course, round up rather
132  * than down while computing this.
133  *
134  * Our n of interest is the largest value that can fit in `size_t', which is
135  * an unsigned type; therefore n = 2^k - 1 for some k, and ⌊lg (n + 2)⌋ = k.
136  * Alas, C doesn't give us k directly, but it can certainly be no more than
137  * `CHAR_BIT*sizeof(size_t)'; since padding bits in integers are extremely
138  * rare, this is usually the exact value.  C permits objects at least
139  * 2^{15} - 1 bytes in size, so this must be at least that large.  In
140  * particular, it's larger than 12, so we can apply this simplification.
141  *
142  * On conventional 32-bit targets, this is 47; on 64-bit targets, it's 93.
143  * Both overestimate by one entry.
144  */
145
146 #define XYLA_AVL_HTMAX (13*(sizeof(size_t)*CHAR_BIT + 8)/9)
147
148 struct xyla_avl_iter {
149   int sp;
150   const struct xyla_bt_node *stack[XYLA_AVL_HTMAX];
151 };
152 struct xyla_avl_riter {
153   int sp;
154   const struct xyla_bt_node *stack[XYLA_AVL_HTMAX];
155 };
156
157 struct xyla_avl_path {
158   int k;
159   struct xyla_bt_node **p[XYLA_AVL_HTMAX + 1];
160 };
161
162 /*----- Miscellaneous utilities -------------------------------------------*/
163
164 extern int xyla_avl_height(const struct xyla_avl_node */*node*/);
165   /* Return the height for the (sub)tree rooted at NODE.  This is primarily
166    * useful as input to `xyla_avl_join' and `xyla_avl_split'.
167    */
168
169 /*----- Iteration ---------------------------------------------------------*/
170
171 extern void xyla_avl_inititer(const struct xyla_bt_node */*root*/,
172                               struct xyla_avl_iter */*it*/);
173   /* Initialize the iterator IT to start returning nodes in left-to-right
174    * order from the tree rooted at ROOT.
175    */
176
177 extern void *xyla_avl_next(struct xyla_avl_iter */*it*/);
178   /* Advance the iterator IT, returning the next node, or null if the
179    * iteration is complete.
180    *
181    * Inserting or removing elements invalidates the iterator.  As a special
182    * exception, it is permitted to free all of the nodes by iterating over
183    * the tree in the obvious manner:
184    *
185    *    xyla_avl_inititer(tree, &it);
186    *    for (;;) {
187    *      node = xyla_avl_next(&it); if (!node) break;
188    *      free(node);
189    *    }
190    *
191    * It's probably better to use `xyla_bt_severfirst' for this task.
192    */
193
194 extern void xyla_avl_initriter(const struct xyla_bt_node */*root*/,
195                                struct xyla_avl_riter */*rit*/);
196   /* Initialize the iterator RIT to start returning nodes in right-to-left
197    * order from the tree rooted at ROOT.
198    */
199
200 extern void *xyla_avl_prev(struct xyla_avl_riter */*rit*/);
201   /* Advance the iterator RIT, returning the previous node, or null if the
202    * iteration is complete.
203    *
204    * Inserting or removing elements invalidates the iterator.  As a special
205    * exception, it is permitted to free all of the nodes by iterating over
206    * the tree in the obvious manner:
207    *
208    *    xyla_avl_inititer(tree, &rit);
209    *    for (;;) {
210    *      node = xyla_avl_next(&rit); if (!node) break;
211    *      free(node);
212    *    }
213    *
214    * It's probably better to use `xyla_bt_severfirst' for this task.
215    */
216
217 /*----- Paths -------------------------------------------------------------*/
218
219 extern void *xyla_avl_current(const struct xyla_avl_path */*path*/);
220   /* Return the node currently designated by PATH, or null if PATH is
221    * empty.
222    */
223
224 extern void xyla_avl_copypath(struct xyla_avl_path */*newpath*/,
225                               const struct xyla_avl_path */*path*/);
226   /* Make a copy of PATH as NEWPATH.  This has the same effect as simply
227    * assigning the path structures, but may be significantly faster because
228    * it only copies the active part of the path vector.
229    */
230
231 extern void *xyla_avl_firstpath(struct xyla_bt_node **/*root*/,
232                                 struct xyla_avl_path */*path*/);
233 extern void *xyla_avl_lastpath(struct xyla_bt_node **/*root*/,
234                                struct xyla_avl_path */*path*/);
235   /* Return the first or last node in the tree, together with a PATH to the
236    * requested node, which can be used to remove them, or to navigate to
237    * other nodes in the tree.  Return null if the tree is empty.
238    */
239
240 extern void *xyla_avl_nextpath(struct xyla_avl_path */*path*/);
241 extern void *xyla_avl_prevpath(struct xyla_avl_path */*path*/);
242   /* Return the next or previous node in the tree, and update the PATH to the
243    * requested node, which can be used to remove them, or to navigate to
244    * other nodes in the tree.
245    *
246    * If the path is full, i.e., refers to an existing node, then the
247    * functions return that node's successor or predecessor.  If the path is
248    * empty, i.e., refers to a space between nodes where a new node can be
249    * inserted, then the functions return the node at the upper or lower end
250    * of the gap, unless the `gap' is actually at an extreme of the tree and
251    * no such node exists.  In the latter case, a null pointer is returned.
252    * The path is modified to refer to the new node, if any, or to the gap at
253    * the appropriate extreme of the tree.
254    */
255
256 extern void xyla_avl_beforepath(struct xyla_avl_path */*path*/);
257 extern void xyla_avl_afterpath(struct xyla_avl_path */*path*/);
258   /* Advance the PATH to just before or after the current node.  The path
259    * thereby becomes empty, suitable to insert an element or split the tree
260    * just before or after the previously selected node.
261    */
262
263 extern void *xyla_avl_rootpath(struct xyla_bt_node **/*root*/,
264                                struct xyla_avl_path */*path*/);
265   /* Initialize PATH to refer to the tree root, given the address ROOT of the
266    * root link, and return this root node.  The resulting path will be empty
267    * if and only if the tree is empty.
268    */
269
270 extern void *xyla_avl_uppath(unsigned */*pos_out*/,
271                              struct xyla_avl_path */*path*/);
272   /* Update the PATH to refer to the parent of the link currently designated;
273    * return this parent node, and set *POS_OUT to the `XYLA_BTPOS_...'
274    * constant describing the link's relation to the parent.  If the path
275    * initially designated the tree's root link, then return null, set
276    * *POS_OUT to `XYLA_BTPOS_ROOT', and leave the path unchanged; otherwise,
277    * the tree becomes full.
278    */
279
280 extern void *xyla_avl_leftpath(struct xyla_avl_path */*path*/);
281 extern void *xyla_avl_rightpath(struct xyla_avl_path */*path*/);
282   /* Update the PATH to refer to the left or right child of the node
283    * currently designated, and set NODE to be this child node.  The PATH must
284    * initially have been full, and may become empty as a result.
285    */
286
287 extern void xyla_avl_replace(const struct xyla_avl_path */*path*/,
288                              struct xyla_avl_node */*node*/);
289   /* Replace the node identified by the PATH with the given NODE.  The node's
290    * links need not be initialized.  Paths and iterators are not invalidated.
291    * It is the caller's responsibility to ensure that any ordering invariants
292    * are respected as a result of the change.
293    */
294
295 extern void xyla_avl_ripple(struct xyla_bt_nodecls */*cls*/,
296                             const struct xyla_avl_path */*path*/);
297   /* Update a node's ancestors -- i.e., call the node class `upd' function on
298    * them, in ascending order -- after it has been modified.  The PATH
299    * describes a full path to the node that has been changed.  The PATH
300    * remains valid.
301    */
302
303 extern int xyla_avl_ascend(xyla_bt_ascendfn */*fn*/,
304                            const struct xyla_avl_path */*path*/,
305                            void */*arg*/);
306   /* Ascend the tree along the PATH, allowing FN to accumulate summary data
307    * from the nodes to the root; see `XYLA_BT_ASCEND' for details.  If FN
308    * returns nonzero, then stop and return the nonzero value; otherwise
309    * return zero.  The PATH remains valid.
310    */
311
312 /*----- Searching ---------------------------------------------------------*/
313
314 extern void *xyla_avl_lookup(struct xyla_bt_nodecls */*cls*/,
315                              struct xyla_bt_node **/*root*/,
316                              xyla_bt_navfn */*navfn*/, void */*arg*/);
317   /* Search for a node within the tree rooted at ROOT.  The search is guided
318    * by NAVFN, passing it ARG at each node.  Return the node that the
319    * function matches, or null if no matching node exists.
320    */
321
322 extern void *xyla_avl_probe(struct xyla_bt_nodecls */*cls*/,
323                             struct xyla_bt_node **/*root*/,
324                             xyla_bt_navfn */*navfn*/, void */*arg*/,
325                             struct xyla_avl_path */*path*/);
326   /* Search for a node within the tree rooted at ROOT.  The search is guided
327    * by NAVFN, passing it ARG at each node.  Record the search path in PATH.
328    * This can be used later, e.g., by `xyla_avl_insert' to insert a new node
329    * if none was found, or by `xyla_avl_remove' to remove the node that was
330    * found.  Return the node that the function matches, or null if no
331    * matching node exists.
332    */
333
334 /*----- Insertion and removal ---------------------------------------------*/
335
336 extern int xyla_avl_insert(struct xyla_bt_nodecls */*cls*/,
337                            struct xyla_avl_path */*path*/,
338                            struct xyla_avl_node */*node*/);
339   /* Add a new node to the tree, in the place determined by the empty PATH.
340    * It's the caller's responsibility to ensure that inserting the node here
341    * respects any ordering invariants.  Returns `XYLA_RC_HTCHG' if the tree
342    * has increased in height, or `XYLA_RC_OK' if its height remains
343    * unchanged.
344    *
345    * The new node is not copied, and its storage must remain valid until the
346    * node is removed or the tree is discarded.
347    */
348
349 extern int xyla_avl_remove(struct xyla_bt_nodecls */*cls*/,
350                            struct xyla_avl_path */*path*/);
351   /* Remove the node identified by the PATH.  The node was allocated by the
352    * caller, and should be freed by the caller in whatever way is
353    * appropriate.  Returns `XYLA_RC_HTCHG' if the tree has decreased in
354    * height, or `XYLA_RC_OK' if its height remains unchanged.
355    */
356
357 /*----- Splitting and joining ---------------------------------------------*/
358
359 extern int xyla_avl_join(struct xyla_bt_nodecls */*cls*/,
360                          struct xyla_bt_node **/*root_out*/,
361                            int */*rootht_out*/,
362                          struct xyla_bt_node **/*left*/, int /*lht*/,
363                          struct xyla_bt_node */*mid*/,
364                          struct xyla_bt_node **/*right*/, int /*rht*/);
365   /* Concatenate the two trees rooted at LEFT and RIGHT in order; if MID is
366    * not null, then place this node between them.  The root of the resulting
367    * tree is stored in *ROOT_OUT.  It's the caller's responsibility to ensure
368    * that this respects any ordering invariants.
369    *
370    * If the heights of the LEFT and RIGHT trees are known, then they can be
371    * passed in as LHT and RHT; otherwise, LHT and/or RHT must be -1.  The
372    * height of the combined tree is stored in *ROOTHT_OUT if this is not
373    * null.
374    *
375    * The ROOT_OUT pointer may equal either LEFT or RIGHT (or, indeed, both,
376    * only if both are empty).  If LEFT is distinct from ROOT_OUT then *LEFT
377    * is set null on exit; similarly, if RIGHT is distinct from ROOT_OUT, then
378    * *RIGHT is set null on exit.
379    *
380    * Returns `XYLA_RC_OK'.
381    */
382
383 extern int xyla_avl_split(struct xyla_bt_nodecls */*cls*/,
384                           struct xyla_bt_node **/*left_out*/,
385                             int */*lht_out*/,
386                           struct xyla_bt_node **/*mid_out*/,
387                           struct xyla_bt_node **/*right_out*/,
388                             int */*rht_out*/,
389                           struct xyla_avl_path */*path*/);
390   /* Split a tree tree into two at the indicated place indicated by the PATH.
391    * Store in *LEFT_OUT and *RIGHT_OUT the roots of trees containing every
392    * node respectively preceding and following the PATH, and in *LHT_OUT and
393    * *RHT_OUT the heights of the respective output trees; either or both of
394    * LHT_OUT and RHT_OUT may be null to discard this information.
395    *
396    * If the PATH is full, i.e., it denotes a node in the input tree, then
397    * that becomes the `middle node', which does not appear in either output
398    * tree; a pointer to this node is stored in *MID_OUT.
399    *
400    * Returns `XYLA_RC_OK'.
401    */
402
403 extern int xyla_avl_splitat(struct xyla_bt_nodecls */*cls*/,
404                             struct xyla_bt_node **/*left_out*/,
405                               int */*lht_out*/,
406                             struct xyla_bt_node **/*mid_out*/,
407                             struct xyla_bt_node **/*right_out*/,
408                               int */*rht_out*/,
409                             struct xyla_bt_node **/*root*/,
410                             const void */*key*/);
411   /* Split the tree rooted at ROOT into two at an indicated KEY.  Store in
412    * *LEFT_OUT and *RIGHT_OUT the roots of trees containing every node whose
413    * key is respectively less than and greater than the KEY, and in *LHT_OUT
414    * and *RHT_OUT the heights of the respective output trees; either or both
415    * of LHT_OUT and RHT_OUT may be null to discard this information.
416    *
417    * If a node matching the KEY exists in the input tree, then that becomes
418    * the `middle node', which does not appear in either output tree; a
419    * pointer to this node is stored in *MID_OUT.
420    *
421    * This operation assumes that the tree traversal ordering matches an
422    * ordering on search keys, which is implemented by the node-class `nav'
423    * function.
424    *
425    * Returns `XYLA_RC_OK'.
426    */
427
428 extern int xyla_avl_splitroot(struct xyla_bt_node **/*left_out*/,
429                                 int */*lht_out*/,
430                               struct xyla_bt_node **/*root_out*/,
431                               struct xyla_bt_node **/*right_out*/,
432                                 int */*rht_out*/,
433                               struct xyla_bt_node **/*root*/, int /*ht*/);
434   /* Split the tree rooted at ROOT into two at its root.  Store in *ROOT_OUT
435    * a pointer to the original root node, or null if the tree was initially
436    * empty; store in *LEFT_OUT and *RIGHT_OUT the root of the original root's
437    * left and right subtrees respectively, and in *LHT_OUT and *RHT_OUT the
438    * heights of the respective output trees; either or both of LHT_OUT and
439    * RHT_OUT may be null to discard this information.  If the initial tree
440    * height is known, it can be passed in as HT; otherwise, HT must be -1.
441    *
442    * Returns `XYLA_RC_OK'.
443    */
444
445 /*----- Set operations ----------------------------------------------------*/
446
447 extern int xyla_avl_unisect(struct xyla_bt_nodecls */*cls*/,
448                             struct xyla_bt_node **/*uni_out*/,
449                               int */*uniht_out*/,
450                             struct xyla_bt_node **/*isect_out*/,
451                               int */*isectht_out*/,
452                             struct xyla_bt_node **/*aroot*/, int /*aht*/,
453                             struct xyla_bt_node **/*broot*/, int /*bht*/);
454   /* Compute the union and intersection of two trees.
455    *
456    * On entry, *AROOT and *BROOT are the roots of two trees a and b, with
457    * their respective heights in AHT and BHT, if the caller knows them, or -1
458    * otherwise.  The trees are considered to represent sets, with one element
459    * per node; the element is determined by the `key' node-class operation.
460    * On exit, *UNI_OUT points to the root of a tree containing (one copy of)
461    * each element present in either a or b, and *ISECT_OUT points to the root
462    * of a tree containing the other copy of each element present in both a
463    * and b; the heights of the output trees are stored in *UNIHT_OUT and
464    * *ISECTHT_OUT, if these are not null.  If AROOT and/or BROOT are distinct
465    * from UNI_OUT and ISECT_OUT, then null pointers are stored in them.  The
466    * original trees are destroyed; each node in the original operands trees
467    * ends up in exactly one of the result trees.
468    *
469    * Returns `XYLA_RC_OK'.
470    */
471
472 extern int xyla_avl_diffsect(struct xyla_bt_nodecls */*cls*/,
473                              struct xyla_bt_node **/*diff_out*/,
474                                int */*diffht_out*/,
475                              struct xyla_bt_node **/*isect_out*/,
476                                int */*isectht_out*/,
477                              struct xyla_bt_node **/*aroot*/, int /*aht*/,
478                              struct xyla_bt_node **/*broot*/);
479   /* Compute the set difference of the two operand trees.
480    *
481    * On entry, *AROOT and *BROOT are the roots of two trees a and b, with a's
482    * height in AHT, if the caller knows it, or -1 otherwise (the height of b
483    * is not significant).  The trees are considered to represent sets, with
484    * one element per node; the element is determined by the `key' node-class
485    * operation.  On exit, *DIFF_OUT points to the root of a tree containing
486    * each element of a but not b, and *ISECT_OUT points to the root of a tree
487    * containing each element of a that's also in b; the heights of the output
488    * trees are stored in *DIFFHT_OUT and *ISECTHT_OUT, if these are not null.
489    * If AROOT and/or BROOT are distinct from DIFF_OUT and ISECT_OUT, then
490    * null pointers are stored in them.  The original a tree is destroyed;
491    * each node in the original operands trees ends up in exactly one of the
492    * result trees.  The input b tree is unchanged.
493    *
494    * Returns `XYLA_RC_OK'.
495    */
496
497 /*----- Checking ----------------------------------------------------------*/
498
499 #ifndef XYLA_FREESTANDING
500
501 extern int xyla_avl_check(struct xyla_bt_nodecls */*cls*/,
502                           struct xyla_bt_node *const */*root*/,
503                           FILE */*fp*/, unsigned /*f*/,
504                           int /*expht*/, void */*arg*/);
505   /* Examine an AVL tree, checking that it satisfies all of the necessary
506    * invariants.  If EXPHT is not equal to -1, then check that the overall
507    * tree height is equal to EXPHT.
508    *
509    * This function uses the `xyla_bt_check' framework; see the description of
510    * that function for details.  Returns `XYLA_RC_OK' on success,
511    * `XYLA_RC_BAD' if problems are found, or some other code if verification
512    * had to finish prematurely.
513    */
514
515 #endif
516
517 /*----- That's all, folks -------------------------------------------------*/
518
519 #endif