1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, see <http://www.gnu.org/licenses/>. */
17 /* Augmented binary tree (ABT) data structure. */
19 /* These library routines have no external dependencies other
20 than the standard C library.
22 If you add routines in this file, please add a corresponding
23 test to abt-test.c. This test program should achieve 100%
24 coverage of lines and branches in this code, as reported by
31 #include "libpspp/abt.h"
35 #include "libpspp/cast.h"
36 #include "libpspp/assertion.h"
38 static struct abt_node **down_link (struct abt *, struct abt_node *);
39 static struct abt_node *skew (struct abt *, struct abt_node *);
40 static struct abt_node *split (struct abt *, struct abt_node *);
42 /* Initializes ABT as an empty ABT that uses COMPARE and
43 REAUGMENT functions, passing in AUX as auxiliary data.
45 The comparison function is optional. If it is null, this
46 indicates that the tree is being used for its augmentations
47 only. ABT functions that compare nodes may not be used with
48 trees that lack comparison functions; contrariwise, other
49 functions that could disrupt the ordering of a tree may not be
50 used if a comparison function is specified. Refer to
51 individual function descriptions for details. */
53 abt_init (struct abt *abt,
54 abt_compare_func *compare,
55 abt_reaugment_func *reaugment,
58 assert (reaugment != NULL);
60 abt->compare = compare;
61 abt->reaugment = reaugment;
65 /* Inserts the given NODE into ABT.
66 Returns a null pointer if successful.
67 Returns the existing node already in ABT equal to NODE, on
69 This function may be used only if ABT has a comparison
72 abt_insert (struct abt *abt, struct abt_node *node)
78 if (abt->root == NULL)
82 abt_reaugmented (abt, node);
86 struct abt_node *p = abt->root;
91 cmp = abt->compare (node, p, abt->aux);
96 if (p->down[dir] == NULL)
100 abt_reaugmented (abt, node);
107 while ((node = node->up) != NULL)
109 node = skew (abt, node);
110 node = split (abt, node);
116 /* Inserts NODE before or after node P in ABT, depending on the
118 If P is null, then the node is inserted as the first node in
119 the tree, if AFTER is true, or the last node, if AFTER is
122 insert_relative (struct abt *abt, const struct abt_node *p, bool after,
123 struct abt_node *node)
125 node->down[0] = NULL;
126 node->down[1] = NULL;
129 if (abt->root == NULL)
134 abt_reaugmented (abt, node);
144 while (p->down[dir] != NULL)
149 CONST_CAST (struct abt_node *, p)->down[dir] = node;
150 node->up = CONST_CAST (struct abt_node *, p);
151 abt_reaugmented (abt, node);
154 while ((node = node->up) != NULL)
156 node = skew (abt, node);
157 node = split (abt, node);
161 /* Inserts NODE after node P in ABT.
162 If P is null, then the node is inserted as the first node in
164 This function may be used only if ABT lacks a comparison
167 abt_insert_after (struct abt *abt,
168 const struct abt_node *p, struct abt_node *node)
170 assert (abt->compare == NULL);
171 insert_relative (abt, p, true, node);
174 /* Inserts NODE before node P in ABT.
175 If P is null, then the node is inserted as the last node in
177 This function may be used only if ABT lacks a comparison
180 abt_insert_before (struct abt *abt,
181 const struct abt_node *p, struct abt_node *node)
183 assert (abt->compare == NULL);
184 insert_relative (abt, p, false, node);
187 /* Deletes P from ABT. */
189 abt_delete (struct abt *abt, struct abt_node *p)
191 struct abt_node **q = down_link (abt, p);
192 struct abt_node *r = p->down[1];
198 else if (r->down[0] == NULL)
200 r->down[0] = p->down[0];
203 if (r->down[0] != NULL)
210 struct abt_node *s = r->down[0];
211 while (s->down[0] != NULL)
214 r->down[0] = s->down[1];
215 s->down[0] = p->down[0];
216 s->down[1] = p->down[1];
222 if (r->down[0] != NULL)
226 abt_reaugmented (abt, p);
228 for (; p != NULL; p = p->up)
229 if ((p->down[0] != NULL ? p->down[0]->level : 0) < p->level - 1
230 || (p->down[1] != NULL ? p->down[1]->level : 0) < p->level - 1)
233 if (p->down[1] != NULL && p->down[1]->level > p->level)
234 p->down[1]->level = p->level;
237 skew (abt, p->down[1]);
238 if (p->down[1]->down[1] != NULL)
239 skew (abt, p->down[1]->down[1]);
242 split (abt, p->down[1]);
246 /* Returns the node with minimum value in ABT, or a null pointer
249 abt_first (const struct abt *abt)
251 struct abt_node *p = abt->root;
253 while (p->down[0] != NULL)
258 /* Returns the node with maximum value in ABT, or a null pointer
261 abt_last (const struct abt *abt)
263 struct abt_node *p = abt->root;
265 while (p->down[1] != NULL)
270 /* Searches ABT for a node equal to TARGET.
271 Returns the node if found, or a null pointer otherwise.
272 This function may be used only if ABT has a comparison
275 abt_find (const struct abt *abt, const struct abt_node *target)
277 const struct abt_node *p;
280 for (p = abt->root; p != NULL; p = p->down[cmp > 0])
282 cmp = abt->compare (target, p, abt->aux);
284 return CONST_CAST (struct abt_node *, p);
290 /* Returns the node in ABT following P in in-order.
291 If P is null, returns the minimum node in ABT.
292 Returns a null pointer if P is the maximum node in ABT or if P
293 is null and ABT is empty. */
295 abt_next (const struct abt *abt, const struct abt_node *p)
298 return abt_first (abt);
299 else if (p->down[1] == NULL)
302 for (q = p->up; ; p = q, q = q->up)
303 if (q == NULL || p == q->down[0])
309 while (p->down[0] != NULL)
311 return CONST_CAST (struct abt_node *, p);
315 /* Returns the node in ABT preceding P in in-order.
316 If P is null, returns the maximum node in ABT.
317 Returns a null pointer if P is the minimum node in ABT or if P
318 is null and ABT is empty. */
320 abt_prev (const struct abt *abt, const struct abt_node *p)
323 return abt_last (abt);
324 else if (p->down[0] == NULL)
327 for (q = p->up; ; p = q, q = q->up)
328 if (q == NULL || p == q->down[1])
334 while (p->down[1] != NULL)
336 return CONST_CAST (struct abt_node *, p);
340 /* Calls ABT's reaugmentation function to compensate for
341 augmentation data in P having been modified. Use abt_changed,
342 instead, if the key data in P has changed.
344 It is not safe to update more than one node's augmentation
345 data, then to call this function for each node. Instead,
346 update a single node's data, call this function, update
347 another node's data, and so on. Alternatively, remove all
348 affected nodes from the tree, update their values, then
349 re-insert all of them. */
351 abt_reaugmented (const struct abt *abt, struct abt_node *p)
353 for (; p != NULL; p = p->up)
354 abt->reaugment (p, abt->aux);
357 /* Moves P around in ABT to compensate for its key having
358 changed. Returns a null pointer if successful. If P's new
359 value is equal to that of some other node in ABT, returns the
360 other node after removing P from ABT.
362 This function is an optimization only if it is likely that P
363 can actually retain its relative position in ABT, e.g. its key
364 has only been adjusted slightly. Otherwise, it is more
365 efficient to simply remove P from ABT, change its key, and
368 It is not safe to update more than one node's key, then to
369 call this function for each node. Instead, update a single
370 node's key, call this function, update another node's key, and
371 so on. Alternatively, remove all affected nodes from the
372 tree, update their keys, then re-insert all of them.
374 This function may be used only if ABT has a comparison
375 function. If it doesn't, then you probably just want
378 abt_changed (struct abt *abt, struct abt_node *p)
380 struct abt_node *prev = abt_prev (abt, p);
381 struct abt_node *next = abt_next (abt, p);
383 if ((prev != NULL && abt->compare (prev, p, abt->aux) >= 0)
384 || (next != NULL && abt->compare (p, next, abt->aux) >= 0))
387 return abt_insert (abt, p);
391 abt_reaugmented (abt, p);
396 /* ABT nodes may be moved around in memory as necessary, e.g. as
397 the result of an realloc operation on a block that contains a
398 node. Once this is done, call this function passing node P
399 that was moved and its ABT before attempting any other
402 It is not safe to move more than one node, then to call this
403 function for each node. Instead, move a single node, call
404 this function, move another node, and so on. Alternatively,
405 remove all affected nodes from the tree, move them, then
406 re-insert all of them.
408 This function may be used only if ABT has a comparison
411 abt_moved (struct abt *abt, struct abt_node *p)
415 int d = p->up->down[0] == NULL || abt->compare (p, p->up, abt->aux) > 0;
420 if (p->down[0] != NULL)
422 if (p->down[1] != NULL)
426 /* Returns the address of the pointer that points down to P
428 static struct abt_node **
429 down_link (struct abt *abt, struct abt_node *p)
431 return (p->up != NULL
432 ? &p->up->down[p->up->down[0] != p]
436 /* Remove a left "horizontal link" at A, if present.
437 Returns the node that occupies the position previously
439 static struct abt_node *
440 skew (struct abt *abt, struct abt_node *a)
442 struct abt_node *b = a->down[0];
443 if (b != NULL && b->level == a->level)
446 a->down[0] = b->down[1];
448 *down_link (abt, a) = b;
450 if (a->down[0] != NULL)
455 abt->reaugment (a, abt->aux);
456 abt->reaugment (b, abt->aux);
464 /* Removes a pair of consecutive right "horizontal links" at A,
466 Returns the node that occupies the position previously
468 static struct abt_node *
469 split (struct abt *abt, struct abt_node *a)
471 struct abt_node *b = a->down[1];
472 if (b != NULL && b->down[1] != NULL && b->down[1]->level == a->level)
475 a->down[1] = b->down[0];
477 *down_link (abt, a) = b;
479 if (a->down[1] != NULL)
486 abt->reaugment (a, abt->aux);
487 abt->reaugment (b, abt->aux);