2 static const char rcsid
[] = "$Id: tree.c,v 1.4 2005/04/27 04:56:39 sra Exp $";
6 * tree - balanced binary tree library
8 * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
9 * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
10 * vix 23jun86 [added delete uar to add for replaced nodes]
11 * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
12 * vix 06feb86 [added tree_mung()]
13 * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
14 * vix 14dec85 [written]
18 * This program text was created by Paul Vixie using examples from the book:
19 * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
20 * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
25 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
26 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
28 * Permission to use, copy, modify, and distribute this software for any
29 * purpose with or without fee is hereby granted, provided that the above
30 * copyright notice and this permission notice appear in all copies.
32 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
33 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
34 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
35 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
37 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
38 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 # define DEBUG_DOMAIN "tree"
45 #include "port_before.h"
50 #include "port_after.h"
52 #include <isc/memcluster.h>
56 static int debugDepth
= 0;
57 static char *debugFuncs
[256];
58 # define ENTER(proc) { \
59 debugFuncs[debugDepth] = proc; \
60 fprintf(stderr, "ENTER(%d:%s.%s)\n", \
61 debugDepth, DEBUG_DOMAIN, \
62 debugFuncs[debugDepth]); \
65 # define RET(value) { \
67 fprintf(stderr, "RET(%d:%s.%s)\n", \
68 debugDepth, DEBUG_DOMAIN, \
69 debugFuncs[debugDepth]); \
74 fprintf(stderr, "RETV(%d:%s.%s)\n", \
75 debugDepth, DEBUG_DOMAIN, \
76 debugFuncs[debugDepth]); \
79 # define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
81 # define ENTER(proc) ;
82 # define RET(value) return (value);
92 static tree
* sprout(tree
**, tree_t
, int *, int (*)(), void (*)());
93 static int delete(tree
**, int (*)(), tree_t
, void (*)(), int *, int *);
94 static void del(tree
**, int *, tree
**, void (*)(), int *);
95 static void bal_L(tree
**, int *);
96 static void bal_R(tree
**, int *);
99 tree_init(tree
**ppr_tree
) {
106 tree_srch(tree
**ppr_tree
, int (*pfi_compare
)(tree_t
, tree_t
), tree_t p_user
) {
110 int i_comp
= (*pfi_compare
)(p_user
, (**ppr_tree
).data
);
113 RET(tree_srch(&(**ppr_tree
).right
,
118 RET(tree_srch(&(**ppr_tree
).left
,
122 /* not higher, not lower... this must be the one.
124 RET((**ppr_tree
).data
)
127 /* grounded. NOT found.
133 tree_add(tree
**ppr_tree
, int (*pfi_compare
)(tree_t
, tree_t
),
134 tree_t p_user
, void (*pfv_uar
)())
136 int i_balance
= FALSE
;
139 if (!sprout(ppr_tree
, p_user
, &i_balance
, pfi_compare
, pfv_uar
))
145 tree_delete(tree
**ppr_p
, int (*pfi_compare
)(tree_t
, tree_t
),
146 tree_t p_user
, void (*pfv_uar
)())
148 int i_balance
= FALSE
, i_uar_called
= FALSE
;
150 ENTER("tree_delete");
151 RET(delete(ppr_p
, pfi_compare
, p_user
, pfv_uar
,
152 &i_balance
, &i_uar_called
))
156 tree_trav(tree
**ppr_tree
, int (*pfi_uar
)(tree_t
)) {
162 if (!tree_trav(&(**ppr_tree
).left
, pfi_uar
))
164 if (!(*pfi_uar
)((**ppr_tree
).data
))
166 if (!tree_trav(&(**ppr_tree
).right
, pfi_uar
))
172 tree_mung(tree
**ppr_tree
, void (*pfv_uar
)(tree_t
)) {
175 tree_mung(&(**ppr_tree
).left
, pfv_uar
);
176 tree_mung(&(**ppr_tree
).right
, pfv_uar
);
178 (*pfv_uar
)((**ppr_tree
).data
);
179 memput(*ppr_tree
, sizeof(tree
));
186 sprout(tree
**ppr
, tree_t p_data
, int *pi_balance
,
187 int (*pfi_compare
)(tree_t
, tree_t
), void (*pfv_delete
)(tree_t
))
194 /* are we grounded? if so, add the node "here" and set the rebalance
198 MSG("grounded. adding new node, setting h=true")
199 *ppr
= (tree
*) memget(sizeof(tree
));
202 (*ppr
)->right
= NULL
;
204 (*ppr
)->data
= p_data
;
210 /* compare the data using routine passed by caller.
212 cmp
= (*pfi_compare
)(p_data
, (*ppr
)->data
);
214 /* if LESS, prepare to move to the left.
217 MSG("LESS. sprouting left.")
218 sub
= sprout(&(*ppr
)->left
, p_data
, pi_balance
,
219 pfi_compare
, pfv_delete
);
220 if (sub
&& *pi_balance
) { /*%< left branch has grown */
221 MSG("LESS: left branch has grown")
222 switch ((*ppr
)->bal
) {
224 /* right branch WAS longer; bal is ok now */
225 MSG("LESS: case 1.. bal restored implicitly")
230 /* balance WAS okay; now left branch longer */
231 MSG("LESS: case 0.. balnce bad but still ok")
235 /* left branch was already too long. rebal */
236 MSG("LESS: case -1: rebalancing")
238 if (p1
->bal
== -1) { /*%< LL */
239 MSG("LESS: single LL")
240 (*ppr
)->left
= p1
->right
;
244 } else { /*%< double LR */
245 MSG("LESS: double LR")
248 p1
->right
= p2
->left
;
251 (*ppr
)->left
= p2
->right
;
272 /* if MORE, prepare to move to the right.
275 MSG("MORE: sprouting to the right")
276 sub
= sprout(&(*ppr
)->right
, p_data
, pi_balance
,
277 pfi_compare
, pfv_delete
);
278 if (sub
&& *pi_balance
) {
279 MSG("MORE: right branch has grown")
281 switch ((*ppr
)->bal
) {
283 MSG("MORE: balance was off, fixed implicitly")
288 MSG("MORE: balance was okay, now off but ok")
292 MSG("MORE: balance was off, need to rebalance")
294 if (p1
->bal
== 1) { /*%< RR */
295 MSG("MORE: single RR")
296 (*ppr
)->right
= p1
->left
;
300 } else { /*%< double RL */
301 MSG("MORE: double RL")
304 p1
->left
= p2
->right
;
307 (*ppr
)->right
= p2
->left
;
329 /* not less, not more: this is the same key! replace...
331 MSG("FOUND: Replacing data value")
334 (*pfv_delete
)((*ppr
)->data
);
335 (*ppr
)->data
= p_data
;
340 delete(tree
**ppr_p
, int (*pfi_compare
)(tree_t
, tree_t
), tree_t p_user
,
341 void (*pfv_uar
)(tree_t
), int *pi_balance
, int *pi_uar_called
)
348 if (*ppr_p
== NULL
) {
349 MSG("key not in tree")
353 i_comp
= (*pfi_compare
)((*ppr_p
)->data
, p_user
);
355 MSG("too high - scan left")
356 i_ret
= delete(&(*ppr_p
)->left
, pfi_compare
, p_user
, pfv_uar
,
357 pi_balance
, pi_uar_called
);
359 bal_L(ppr_p
, pi_balance
);
360 } else if (i_comp
< 0) {
361 MSG("too low - scan right")
362 i_ret
= delete(&(*ppr_p
)->right
, pfi_compare
, p_user
, pfv_uar
,
363 pi_balance
, pi_uar_called
);
365 bal_R(ppr_p
, pi_balance
);
369 if (pr_q
->right
== NULL
) {
370 MSG("right subtree null")
373 } else if (pr_q
->left
== NULL
) {
374 MSG("right subtree non-null, left subtree null")
375 *ppr_p
= pr_q
->right
;
378 MSG("neither subtree null")
379 del(&pr_q
->left
, pi_balance
, &pr_q
,
380 pfv_uar
, pi_uar_called
);
382 bal_L(ppr_p
, pi_balance
);
384 if (!*pi_uar_called
&& pfv_uar
)
385 (*pfv_uar
)(pr_q
->data
);
386 /* Thanks to wuth@castrov.cuc.ab.ca for the following stmt. */
387 memput(pr_q
, sizeof(tree
));
394 del(tree
**ppr_r
, int *pi_balance
, tree
**ppr_q
,
395 void (*pfv_uar
)(tree_t
), int *pi_uar_called
)
399 if ((*ppr_r
)->right
!= NULL
) {
400 del(&(*ppr_r
)->right
, pi_balance
, ppr_q
,
401 pfv_uar
, pi_uar_called
);
403 bal_R(ppr_r
, pi_balance
);
406 (*pfv_uar
)((*ppr_q
)->data
);
407 *pi_uar_called
= TRUE
;
408 (*ppr_q
)->data
= (*ppr_r
)->data
;
410 *ppr_r
= (*ppr_r
)->left
;
418 bal_L(tree
**ppr_p
, int *pi_balance
) {
423 MSG("left branch has shrunk")
425 switch ((*ppr_p
)->bal
) {
427 MSG("was imbalanced, fixed implicitly")
431 MSG("was okay, is now one off")
436 MSG("was already off, this is too much")
437 p1
= (*ppr_p
)->right
;
441 (*ppr_p
)->right
= p1
->left
;
458 p1
->left
= p2
->right
;
460 (*ppr_p
)->right
= p2
->left
;
478 bal_R(tree
**ppr_p
, int *pi_balance
) {
483 MSG("right branch has shrunk")
484 switch ((*ppr_p
)->bal
) {
486 MSG("was imbalanced, fixed implicitly")
490 MSG("was okay, is now one off")
495 MSG("was already off, this is too much")
500 (*ppr_p
)->left
= p1
->right
;
517 p1
->right
= p2
->left
;
519 (*ppr_p
)->left
= p2
->right
;