3 * Insertion and removal for treaps
5 * (c) 2024 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Xyla, a library of binary trees.
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.
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.
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/>.
26 /*----- Header files ------------------------------------------------------*/
31 /*----- Main code ---------------------------------------------------------*/
33 int xyla_treap_insert(struct xyla_bt_nodecls *cls,
34 struct xyla_treap_path *path,
35 struct xyla_treap_node *node)
37 /* Add a new node to the tree, in the place determined by the empty PATH.
38 * It's the caller's responsibility to ensure that inserting the node here
39 * respects any ordering invariants.
41 * The new node is not copied, and its storage must remain valid until the
42 * node is removed or the tree is discarded.
44 * Returns `XYLA_RC_OK'.
47 struct xyla_treap_node *p, *l, *r;
48 struct xyla_bt_node **nlink, **plink;
49 xyla_bt_updfn *updfn = cls ? cls->ops->upd : 0;
50 size_t nwt = node->trp.wt, pwt;
53 /* The new node is notionally attached to its parent, but may be too light
54 * to stay here. Allow it to float up to its proper resting place. We
55 * don't actually link it into the tree until the end.
57 nlink = path->p[k]; XYLA__ASSERT(!*nlink); l = r = 0;
60 /* If we're at the root then stop here. */
63 node->bt.left = l ? &l->bt : 0;
64 node->bt.right = r ? &r->bt : 0;
65 if (updfn) updfn(cls, &node->bt);
69 /* Fetch the parent node. If it's not heavier than the new node, then we
72 plink = path->p[--k]; p = TREAP_NODE(*plink); pwt = p->trp.wt;
75 node->bt.left = l ? &l->bt : 0;
76 node->bt.right = r ? &r->bt : 0;
77 if (updfn) { updfn(cls, &node->bt); updfn(cls, &p->bt); }
81 /* The node is lighter than its parent, and so must float up. Adjust
84 if (nlink == &p->bt.left)
85 #define FIXUP_INSERT(left, l, right, r) do { \
86 /* The new node is currently the left child. \
96 V( if (xyla__verbout && (xyla__verbose&XYLA__VF_INSERT)) \
97 fputs("XYLA-TREAP INSERT " #left " child\n", \
99 p->bt.left = r ? &r->bt : 0; r = p; \
101 FIXUP_INSERT(left, l, right, r);
103 FIXUP_INSERT(right, r, left, l);
106 /* And ascend the tree. */
107 if (updfn) updfn(cls, &p->bt);
111 /* Follow the rest of the path up to the root, updating the nodes. */
112 if (updfn) while (k) updfn(cls, *path->p[--k]);
118 int xyla_treap_remove(struct xyla_bt_nodecls *cls,
119 struct xyla_treap_path *path)
121 /* Remove the node identified by the PATH. The node was allocated by the
122 * caller, and should be freed by the caller in whatever way is
125 * Returns `XYLA_RC_OK'.
128 struct xyla_treap_node *n, *l, *r;
129 struct xyla_bt_node **nlink;
130 xyla_bt_updfn *updfn = cls ? cls->ops->upd : 0;
134 /* Collect the node and its children. */
136 n = TREAP_NODE(*nlink); XYLA__ASSERT(n);
137 l = TREAP_NODE(n->bt.left); r = TREAP_NODE(n->bt.right);
140 /* The node has a null left link, so the job is easy: replace the node by
144 *nlink = r ? &r->bt : 0;
146 /* The node has a null right link. */
148 *nlink = l ? &l->bt : 0;
150 /* The node has two active children. We're going to pretend that our
151 * node has suddenly become very heavy, so it has to sink to the bottom
155 /* Start by collecting the child weights. */
156 lwt = l->trp.wt; rwt = r->trp.wt;
158 /* Descend the tree until one of the links becomes null. */
160 if (k >= XYLA_TREAP_HTMAX) xyla__treap_boundfail();
162 /* Replace the node with its lighter child. */
164 #define FIXUP_REMOVE(left, l, lwt, right, r, rwt) do { \
165 /* The left child is lighter. Rearrange links and descend. \
176 V( if (xyla__verbout && (xyla__verbose&XYLA__VF_REMOVE)) \
177 fputs("XYLA-TREAP REMOVE float " #left " child\n", \
179 *nlink = &l->bt; nlink = path->p[++k] = &l->bt.right; \
180 l = TREAP_NODE(l->bt.right); \
182 /* If the new left link is null then we're done. */ \
183 if (!l) { *nlink = &r->bt; goto done; } \
186 FIXUP_REMOVE(left, l, lwt, right, r, rwt);
188 FIXUP_REMOVE(right, r, rwt, left, l, lwt);
194 /* Follow the rest of the path up to the root, updating the nodes. */
195 if (updfn) while (k) updfn(cls, *path->p[--k]);
201 /*----- That's all, folks -------------------------------------------------*/