Home | History | Annotate | Line # | Download | only in isc
tree.c revision 1.1.1.1.4.2
      1 /*	$NetBSD: tree.c,v 1.1.1.1.4.2 2011/01/06 21:42:19 riz Exp $	*/
      2 
      3 #ifndef LINT
      4 static const char rcsid[] = "Id: tree.c,v 1.4 2005/04/27 04:56:39 sra Exp";
      5 #endif
      6 
      7 /*%
      8  * tree - balanced binary tree library
      9  *
     10  * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
     11  * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
     12  * vix 23jun86 [added delete uar to add for replaced nodes]
     13  * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
     14  * vix 06feb86 [added tree_mung()]
     15  * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
     16  * vix 14dec85 [written]
     17  */
     18 
     19 /*%
     20  * This program text was created by Paul Vixie using examples from the book:
     21  * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
     22  * 0-13-022005-1.  Any errors in the conversion from Modula-2 to C are Paul
     23  * Vixie's.
     24  */
     25 
     26 /*
     27  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
     28  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
     29  *
     30  * Permission to use, copy, modify, and distribute this software for any
     31  * purpose with or without fee is hereby granted, provided that the above
     32  * copyright notice and this permission notice appear in all copies.
     33  *
     34  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     35  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     36  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     37  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     39  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     40  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     41  */
     42 
     43 /*#define		DEBUG	"tree"*/
     44 
     45 #include "port_before.h"
     46 
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 
     50 #include "port_after.h"
     51 
     52 #include <isc/memcluster.h>
     53 #include <isc/tree.h>
     54 
     55 #ifdef DEBUG
     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, \
     62 				debugFuncs[debugDepth]); \
     63 			debugDepth++; \
     64 		}
     65 # define RET(value) { \
     66 			debugDepth--; \
     67 			fprintf(stderr, "RET(%d:%s.%s)\n", \
     68 				debugDepth, DEBUG, \
     69 				debugFuncs[debugDepth]); \
     70 			return (value); \
     71 		}
     72 # define RETV { \
     73 			debugDepth--; \
     74 			fprintf(stderr, "RETV(%d:%s.%s)\n", \
     75 				debugDepth, DEBUG, \
     76 				debugFuncs[debugDepth]); \
     77 			return; \
     78 		}
     79 # define MSG(msg)	fprintf(stderr, "MSG(%s)\n", msg);
     80 #else
     81 # define ENTER(proc)	;
     82 # define RET(value)	return (value);
     83 # define RETV		return;
     84 # define MSG(msg)	;
     85 #endif
     86 
     87 #ifndef TRUE
     88 # define TRUE		1
     89 # define FALSE		0
     90 #endif
     91 
     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 *);
     97 
     98 void
     99 tree_init(tree **ppr_tree) {
    100 	ENTER("tree_init")
    101 	*ppr_tree = NULL;
    102 	RETV
    103 }
    104 
    105 tree_t
    106 tree_srch(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t), tree_t	p_user) {
    107 	ENTER("tree_srch")
    108 
    109 	if (*ppr_tree) {
    110 		int i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
    111 
    112 		if (i_comp > 0)
    113 			RET(tree_srch(&(**ppr_tree).right,
    114 				      pfi_compare,
    115 				      p_user))
    116 
    117 		if (i_comp < 0)
    118 			RET(tree_srch(&(**ppr_tree).left,
    119 				      pfi_compare,
    120 				      p_user))
    121 
    122 		/* not higher, not lower... this must be the one.
    123 		 */
    124 		RET((**ppr_tree).data)
    125 	}
    126 
    127 	/* grounded. NOT found.
    128 	 */
    129 	RET(NULL)
    130 }
    131 
    132 tree_t
    133 tree_add(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t),
    134 	 tree_t p_user, void (*pfv_uar)())
    135 {
    136 	int i_balance = FALSE;
    137 
    138 	ENTER("tree_add")
    139 	if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
    140 		RET(NULL)
    141 	RET(p_user)
    142 }
    143 
    144 int
    145 tree_delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t),
    146 	    tree_t p_user, void	(*pfv_uar)())
    147 {
    148 	int i_balance = FALSE, i_uar_called = FALSE;
    149 
    150 	ENTER("tree_delete");
    151 	RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
    152 		   &i_balance, &i_uar_called))
    153 }
    154 
    155 int
    156 tree_trav(tree **ppr_tree, int (*pfi_uar)(tree_t)) {
    157 	ENTER("tree_trav")
    158 
    159 	if (!*ppr_tree)
    160 		RET(TRUE)
    161 
    162 	if (!tree_trav(&(**ppr_tree).left, pfi_uar))
    163 		RET(FALSE)
    164 	if (!(*pfi_uar)((**ppr_tree).data))
    165 		RET(FALSE)
    166 	if (!tree_trav(&(**ppr_tree).right, pfi_uar))
    167 		RET(FALSE)
    168 	RET(TRUE)
    169 }
    170 
    171 void
    172 tree_mung(tree **ppr_tree, void	(*pfv_uar)(tree_t)) {
    173 	ENTER("tree_mung")
    174 	if (*ppr_tree) {
    175 		tree_mung(&(**ppr_tree).left, pfv_uar);
    176 		tree_mung(&(**ppr_tree).right, pfv_uar);
    177 		if (pfv_uar)
    178 			(*pfv_uar)((**ppr_tree).data);
    179 		memput(*ppr_tree, sizeof(tree));
    180 		*ppr_tree = NULL;
    181 	}
    182 	RETV
    183 }
    184 
    185 static 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))
    188 {
    189 	tree *p1, *p2, *sub;
    190 	int cmp;
    191 
    192 	ENTER("sprout")
    193 
    194 	/* are we grounded?  if so, add the node "here" and set the rebalance
    195 	 * flag, then exit.
    196 	 */
    197 	if (!*ppr) {
    198 		MSG("grounded. adding new node, setting h=true")
    199 		*ppr = (tree *) memget(sizeof(tree));
    200 		if (*ppr) {
    201 			(*ppr)->left = NULL;
    202 			(*ppr)->right = NULL;
    203 			(*ppr)->bal = 0;
    204 			(*ppr)->data = p_data;
    205 			*pi_balance = TRUE;
    206 		}
    207 		RET(*ppr);
    208 	}
    209 
    210 	/* compare the data using routine passed by caller.
    211 	 */
    212 	cmp = (*pfi_compare)(p_data, (*ppr)->data);
    213 
    214 	/* if LESS, prepare to move to the left.
    215 	 */
    216 	if (cmp < 0) {
    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) {
    223 			case 1:
    224 				/* right branch WAS longer; bal is ok now */
    225 				MSG("LESS: case 1.. bal restored implicitly")
    226 				(*ppr)->bal = 0;
    227 				*pi_balance = FALSE;
    228 				break;
    229 			case 0:
    230 				/* balance WAS okay; now left branch longer */
    231 				MSG("LESS: case 0.. balnce bad but still ok")
    232 				(*ppr)->bal = -1;
    233 				break;
    234 			case -1:
    235 				/* left branch was already too long. rebal */
    236 				MSG("LESS: case -1: rebalancing")
    237 				p1 = (*ppr)->left;
    238 				if (p1->bal == -1) {		/*%< LL */
    239 					MSG("LESS: single LL")
    240 					(*ppr)->left = p1->right;
    241 					p1->right = *ppr;
    242 					(*ppr)->bal = 0;
    243 					*ppr = p1;
    244 				} else {			/*%< double LR */
    245 					MSG("LESS: double LR")
    246 
    247 					p2 = p1->right;
    248 					p1->right = p2->left;
    249 					p2->left = p1;
    250 
    251 					(*ppr)->left = p2->right;
    252 					p2->right = *ppr;
    253 
    254 					if (p2->bal == -1)
    255 						(*ppr)->bal = 1;
    256 					else
    257 						(*ppr)->bal = 0;
    258 
    259 					if (p2->bal == 1)
    260 						p1->bal = -1;
    261 					else
    262 						p1->bal = 0;
    263 					*ppr = p2;
    264 				} /*else*/
    265 				(*ppr)->bal = 0;
    266 				*pi_balance = FALSE;
    267 			} /*switch*/
    268 		} /*if*/
    269 		RET(sub)
    270 	} /*if*/
    271 
    272 	/* if MORE, prepare to move to the right.
    273 	 */
    274 	if (cmp > 0) {
    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")
    280 
    281 			switch ((*ppr)->bal) {
    282 			case -1:
    283 				MSG("MORE: balance was off, fixed implicitly")
    284 				(*ppr)->bal = 0;
    285 				*pi_balance = FALSE;
    286 				break;
    287 			case 0:
    288 				MSG("MORE: balance was okay, now off but ok")
    289 				(*ppr)->bal = 1;
    290 				break;
    291 			case 1:
    292 				MSG("MORE: balance was off, need to rebalance")
    293 				p1 = (*ppr)->right;
    294 				if (p1->bal == 1) {		/*%< RR */
    295 					MSG("MORE: single RR")
    296 					(*ppr)->right = p1->left;
    297 					p1->left = *ppr;
    298 					(*ppr)->bal = 0;
    299 					*ppr = p1;
    300 				} else {			/*%< double RL */
    301 					MSG("MORE: double RL")
    302 
    303 					p2 = p1->left;
    304 					p1->left = p2->right;
    305 					p2->right = p1;
    306 
    307 					(*ppr)->right = p2->left;
    308 					p2->left = *ppr;
    309 
    310 					if (p2->bal == 1)
    311 						(*ppr)->bal = -1;
    312 					else
    313 						(*ppr)->bal = 0;
    314 
    315 					if (p2->bal == -1)
    316 						p1->bal = 1;
    317 					else
    318 						p1->bal = 0;
    319 
    320 					*ppr = p2;
    321 				} /*else*/
    322 				(*ppr)->bal = 0;
    323 				*pi_balance = FALSE;
    324 			} /*switch*/
    325 		} /*if*/
    326 		RET(sub)
    327 	} /*if*/
    328 
    329 	/* not less, not more: this is the same key!  replace...
    330 	 */
    331 	MSG("FOUND: Replacing data value")
    332 	*pi_balance = FALSE;
    333 	if (pfv_delete)
    334 		(*pfv_delete)((*ppr)->data);
    335 	(*ppr)->data = p_data;
    336 	RET(*ppr)
    337 }
    338 
    339 static int
    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)
    342 {
    343 	tree *pr_q;
    344 	int i_comp, i_ret;
    345 
    346 	ENTER("delete")
    347 
    348 	if (*ppr_p == NULL) {
    349 		MSG("key not in tree")
    350 		RET(FALSE)
    351 	}
    352 
    353 	i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
    354 	if (i_comp > 0) {
    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);
    358 		if (*pi_balance)
    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);
    364 		if (*pi_balance)
    365 			bal_R(ppr_p, pi_balance);
    366 	} else {
    367 		MSG("equal")
    368 		pr_q = *ppr_p;
    369 		if (pr_q->right == NULL) {
    370 			MSG("right subtree null")
    371 			*ppr_p = pr_q->left;
    372 			*pi_balance = TRUE;
    373 		} else if (pr_q->left == NULL) {
    374 			MSG("right subtree non-null, left subtree null")
    375 			*ppr_p = pr_q->right;
    376 			*pi_balance = TRUE;
    377 		} else {
    378 			MSG("neither subtree null")
    379 			del(&pr_q->left, pi_balance, &pr_q,
    380 			    pfv_uar, pi_uar_called);
    381 			if (*pi_balance)
    382 				bal_L(ppr_p, pi_balance);
    383 		}
    384 		if (!*pi_uar_called && pfv_uar)
    385 			(*pfv_uar)(pr_q->data);
    386 		/* Thanks to wuth (at) castrov.cuc.ab.ca for the following stmt. */
    387 		memput(pr_q, sizeof(tree));
    388 		i_ret = TRUE;
    389 	}
    390 	RET(i_ret)
    391 }
    392 
    393 static void
    394 del(tree **ppr_r, int *pi_balance, tree **ppr_q,
    395     void (*pfv_uar)(tree_t), int *pi_uar_called)
    396 {
    397 	ENTER("del")
    398 
    399 	if ((*ppr_r)->right != NULL) {
    400 		del(&(*ppr_r)->right, pi_balance, ppr_q,
    401 		    pfv_uar, pi_uar_called);
    402 		if (*pi_balance)
    403 			bal_R(ppr_r, pi_balance);
    404 	} else {
    405 		if (pfv_uar)
    406 			(*pfv_uar)((*ppr_q)->data);
    407 		*pi_uar_called = TRUE;
    408 		(*ppr_q)->data = (*ppr_r)->data;
    409 		*ppr_q = *ppr_r;
    410 		*ppr_r = (*ppr_r)->left;
    411 		*pi_balance = TRUE;
    412 	}
    413 
    414 	RETV
    415 }
    416 
    417 static void
    418 bal_L(tree **ppr_p, int *pi_balance) {
    419 	tree *p1, *p2;
    420 	int b1, b2;
    421 
    422 	ENTER("bal_L")
    423 	MSG("left branch has shrunk")
    424 
    425 	switch ((*ppr_p)->bal) {
    426 	case -1:
    427 		MSG("was imbalanced, fixed implicitly")
    428 		(*ppr_p)->bal = 0;
    429 		break;
    430 	case 0:
    431 		MSG("was okay, is now one off")
    432 		(*ppr_p)->bal = 1;
    433 		*pi_balance = FALSE;
    434 		break;
    435 	case 1:
    436 		MSG("was already off, this is too much")
    437 		p1 = (*ppr_p)->right;
    438 		b1 = p1->bal;
    439 		if (b1 >= 0) {
    440 			MSG("single RR")
    441 			(*ppr_p)->right = p1->left;
    442 			p1->left = *ppr_p;
    443 			if (b1 == 0) {
    444 				MSG("b1 == 0")
    445 				(*ppr_p)->bal = 1;
    446 				p1->bal = -1;
    447 				*pi_balance = FALSE;
    448 			} else {
    449 				MSG("b1 != 0")
    450 				(*ppr_p)->bal = 0;
    451 				p1->bal = 0;
    452 			}
    453 			*ppr_p = p1;
    454 		} else {
    455 			MSG("double RL")
    456 			p2 = p1->left;
    457 			b2 = p2->bal;
    458 			p1->left = p2->right;
    459 			p2->right = p1;
    460 			(*ppr_p)->right = p2->left;
    461 			p2->left = *ppr_p;
    462 			if (b2 == 1)
    463 				(*ppr_p)->bal = -1;
    464 			else
    465 				(*ppr_p)->bal = 0;
    466 			if (b2 == -1)
    467 				p1->bal = 1;
    468 			else
    469 				p1->bal = 0;
    470 			*ppr_p = p2;
    471 			p2->bal = 0;
    472 		}
    473 	}
    474 	RETV
    475 }
    476 
    477 static void
    478 bal_R(tree **ppr_p, int *pi_balance) {
    479 	tree *p1, *p2;
    480 	int b1, b2;
    481 
    482 	ENTER("bal_R")
    483 	MSG("right branch has shrunk")
    484 	switch ((*ppr_p)->bal) {
    485 	case 1:
    486 		MSG("was imbalanced, fixed implicitly")
    487 		(*ppr_p)->bal = 0;
    488 		break;
    489 	case 0:
    490 		MSG("was okay, is now one off")
    491 		(*ppr_p)->bal = -1;
    492 		*pi_balance = FALSE;
    493 		break;
    494 	case -1:
    495 		MSG("was already off, this is too much")
    496 		p1 = (*ppr_p)->left;
    497 		b1 = p1->bal;
    498 		if (b1 <= 0) {
    499 			MSG("single LL")
    500 			(*ppr_p)->left = p1->right;
    501 			p1->right = *ppr_p;
    502 			if (b1 == 0) {
    503 				MSG("b1 == 0")
    504 				(*ppr_p)->bal = -1;
    505 				p1->bal = 1;
    506 				*pi_balance = FALSE;
    507 			} else {
    508 				MSG("b1 != 0")
    509 				(*ppr_p)->bal = 0;
    510 				p1->bal = 0;
    511 			}
    512 			*ppr_p = p1;
    513 		} else {
    514 			MSG("double LR")
    515 			p2 = p1->right;
    516 			b2 = p2->bal;
    517 			p1->right = p2->left;
    518 			p2->left = p1;
    519 			(*ppr_p)->left = p2->right;
    520 			p2->right = *ppr_p;
    521 			if (b2 == -1)
    522 				(*ppr_p)->bal = 1;
    523 			else
    524 				(*ppr_p)->bal = 0;
    525 			if (b2 == 1)
    526 				p1->bal = -1;
    527 			else
    528 				p1->bal = 0;
    529 			*ppr_p = p2;
    530 			p2->bal = 0;
    531 		}
    532 	}
    533 	RETV
    534 }
    535 
    536 /*! \file */
    537