1 /* PSPP - computes sample statistics.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 /* Augmented binary tree (ABT) data structure. */
21 /* These library routines have no external dependencies other
22 than the standard C library.
24 If you add routines in this file, please add a corresponding
25 test to abt-test.c. This test program should achieve 100%
26 coverage of lines and branches in this code, as reported by
33 #include <libpspp/abt.h>
35 static struct abt_node **down_link (struct abt *, struct abt_node *);
36 static struct abt_node *skew (struct abt *, struct abt_node *);
37 static struct abt_node *split (struct abt *, struct abt_node *);
39 /* Initializes ABT as an empty ABT that uses COMPARE and
40 REAUGMENT functions, passing in AUX as auxiliary data. */
42 abt_init (struct abt *abt,
43 abt_compare_func *compare,
44 abt_reaugment_func *reaugment,
48 abt->compare = compare;
49 abt->reaugment = reaugment;
53 /* Inserts the given NODE into ABT.
54 Returns a null pointer if successful.
55 Returns the existing node already in ABT equal to NODE, on
58 abt_insert (struct abt *abt, struct abt_node *node)
64 if (abt->root == NULL)
68 abt_reaugmented (abt, node);
72 struct abt_node *p = abt->root;
77 cmp = abt->compare (node, p, abt->aux);
82 if (p->down[dir] == NULL)
86 abt_reaugmented (abt, node);
93 while ((node = node->up) != NULL)
95 node = skew (abt, node);
96 node = split (abt, node);
102 /* Deletes P from ABT. */
104 abt_delete (struct abt *abt, struct abt_node *p)
106 struct abt_node **q = down_link (abt, p);
107 struct abt_node *r = p->down[1];
113 else if (r->down[0] == NULL)
115 r->down[0] = p->down[0];
118 if (r->down[0] != NULL)
125 struct abt_node *s = r->down[0];
126 while (s->down[0] != NULL)
129 r->down[0] = s->down[1];
130 s->down[0] = p->down[0];
131 s->down[1] = p->down[1];
137 if (r->down[0] != NULL)
141 abt_reaugmented (abt, p);
143 for (; p != NULL; p = p->up)
144 if ((p->down[0] != NULL ? p->down[0]->level : 0) < p->level - 1
145 || (p->down[1] != NULL ? p->down[1]->level : 0) < p->level - 1)
148 if (p->down[1] != NULL && p->down[1]->level > p->level)
149 p->down[1]->level = p->level;
152 skew (abt, p->down[1]);
153 if (p->down[1]->down[1] != NULL)
154 skew (abt, p->down[1]->down[1]);
157 split (abt, p->down[1]);
161 /* Returns the node with minimum value in ABT, or a null pointer
164 abt_first (const struct abt *abt)
166 struct abt_node *p = abt->root;
168 while (p->down[0] != NULL)
173 /* Returns the node with maximum value in ABT, or a null pointer
176 abt_last (const struct abt *abt)
178 struct abt_node *p = abt->root;
180 while (p->down[1] != NULL)
185 /* Searches ABT for a node equal to TARGET.
186 Returns the node if found, or a null pointer otherwise. */
188 abt_find (const struct abt *abt, const struct abt_node *target)
190 const struct abt_node *p;
193 for (p = abt->root; p != NULL; p = p->down[cmp > 0])
195 cmp = abt->compare (target, p, abt->aux);
197 return (struct abt_node *) p;
203 /* Returns the node in ABT following P in in-order.
204 If P is null, returns the minimum node in ABT.
205 Returns a null pointer if P is the maximum node in ABT or if P
206 is null and ABT is empty. */
208 abt_next (const struct abt *abt, const struct abt_node *p)
211 return abt_first (abt);
212 else if (p->down[1] == NULL)
215 for (q = p->up; ; p = q, q = q->up)
216 if (q == NULL || p == q->down[0])
222 while (p->down[0] != NULL)
224 return (struct abt_node *) p;
228 /* Returns the node in ABT preceding P in in-order.
229 If P is null, returns the maximum node in ABT.
230 Returns a null pointer if P is the minimum node in ABT or if P
231 is null and ABT is empty. */
233 abt_prev (const struct abt *abt, const struct abt_node *p)
236 return abt_last (abt);
237 else if (p->down[0] == NULL)
240 for (q = p->up; ; p = q, q = q->up)
241 if (q == NULL || p == q->down[1])
247 while (p->down[1] != NULL)
249 return (struct abt_node *) p;
253 /* Calls ABT's reaugmentation function to compensate for
254 augmentation data in P having been modified. Use abt_changed,
255 instead, if the key data in P has changed.
257 It is not safe to update more than one node's augmentation
258 data, then to call this function for each node. Instead,
259 update a single node's data, call this function, update
260 another node's data, and so on. Alternatively, remove all
261 affected nodes from the tree, update their values, then
262 re-insert all of them. */
264 abt_reaugmented (const struct abt *abt, struct abt_node *p)
266 for (; p != NULL; p = p->up)
267 abt->reaugment (p, p->down[0], p->down[1], abt->aux);
270 /* Moves P around in ABT to compensate for its key having
271 changed. Returns a null pointer if successful. If P's new
272 value is equal to that of some other node in ABT, returns the
273 other node after removing P from ABT.
275 This function is an optimization only if it is likely that P
276 can actually retain its relative position in ABT, e.g. its key
277 has only been adjusted slightly. Otherwise, it is more
278 efficient to simply remove P from ABT, change its key, and
281 It is not safe to update more than one node's key, then to
282 call this function for each node. Instead, update a single
283 node's key, call this function, update another node's key, and
284 so on. Alternatively, remove all affected nodes from the
285 tree, update their keys, then re-insert all of them. */
287 abt_changed (struct abt *abt, struct abt_node *p)
289 struct abt_node *prev = abt_prev (abt, p);
290 struct abt_node *next = abt_next (abt, p);
292 if ((prev != NULL && abt->compare (prev, p, abt->aux) >= 0)
293 || (next != NULL && abt->compare (p, next, abt->aux) >= 0))
296 return abt_insert (abt, p);
300 abt_reaugmented (abt, p);
305 /* ABT nodes may be moved around in memory as necessary, e.g. as
306 the result of an realloc operation on a block that contains a
307 node. Once this is done, call this function passing node P
308 that was moved and its ABT before attempting any other
311 It is not safe to move more than one node, then to call this
312 function for each node. Instead, move a single node, call
313 this function, move another node, and so on. Alternatively,
314 remove all affected nodes from the tree, move them, then
315 re-insert all of them. */
317 abt_moved (struct abt *abt, struct abt_node *p)
321 int d = p->up->down[0] == NULL || abt->compare (p, p->up, abt->aux) > 0;
326 if (p->down[0] != NULL)
328 if (p->down[1] != NULL)
332 /* Returns the address of the pointer that points down to P
334 static struct abt_node **
335 down_link (struct abt *abt, struct abt_node *p)
337 return (p->up != NULL
338 ? &p->up->down[p->up->down[0] != p]
342 /* Remove a left "horizontal link" at A, if present.
343 Returns the node that occupies the position previously
345 static struct abt_node *
346 skew (struct abt *abt, struct abt_node *a)
348 struct abt_node *b = a->down[0];
349 if (b != NULL && b->level == a->level)
352 a->down[0] = b->down[1];
354 *down_link (abt, a) = b;
356 if (a->down[0] != NULL)
361 abt->reaugment (a, a->down[0], a->down[1], abt->aux);
362 abt->reaugment (b, b->down[0], b->down[1], abt->aux);
370 /* Removes a pair of consecutive right "horizontal links" at A,
372 Returns the node that occupies the position previously
374 static struct abt_node *
375 split (struct abt *abt, struct abt_node *a)
377 struct abt_node *b = a->down[1];
378 if (b != NULL && b->down[1] != NULL && b->down[1]->level == a->level)
381 a->down[1] = b->down[0];
383 *down_link (abt, a) = b;
385 if (a->down[1] != NULL)
392 abt->reaugment (a, a->down[0], a->down[1], abt->aux);
393 abt->reaugment (b, b->down[0], b->down[1], abt->aux);