static ubi_btNodePtr Neighbor( register ubi_btNodePtr P, register int whichway ) /* ------------------------------------------------------------------------ ** * Given starting point p, return the (key order) next or preceeding node * in the tree. * * Input: P - Pointer to our starting place node. * whichway - the direction in which to travel to find the * neighbor, i.e., the RIGHT neighbor or the LEFT * neighbor. * * Output: A pointer to the neighboring node, or NULL if P was NULL. * * Notes: If whichway is PARENT, the results are unpredictable. * ------------------------------------------------------------------------ ** */ { if( P ) { if( NULL != P->Link[ whichway ] ) return( SubSlide( P->Link[ whichway ], (char)ubi_trRevWay(whichway) ) ); else while( NULL != P->Link[ ubi_trPARENT ] ) { if( whichway == P->gender ) P = P->Link[ ubi_trPARENT ]; else return( P->Link[ ubi_trPARENT ] ); } } return( NULL ); } /* Neighbor */
ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) /* ------------------------------------------------------------------------ ** * Returns a pointer to a leaf node. * * Input: leader - Pointer to a node at which to start the descent. * * Output: A pointer to a leaf node selected in a somewhat arbitrary * manner. * * Notes: I wrote this function because I was using splay trees as a * database cache. The cache had a maximum size on it, and I * needed a way of choosing a node to sacrifice if the cache * became full. In a splay tree, less recently accessed nodes * tend toward the bottom of the tree, meaning that leaf nodes * are good candidates for removal. (I really can't think of * any other reason to use this function.) * + In a simple binary tree or an AVL tree, the most recently * added nodes tend to be nearer the bottom, making this a *bad* * way to choose which node to remove from the cache. * + Randomizing the traversal order is probably a good idea. You * can improve the randomization of leaf node selection by passing * in pointers to nodes other than the root node each time. A * pointer to any node in the tree will do. Of course, if you * pass a pointer to a leaf node you'll get the same thing back. * * ------------------------------------------------------------------------ ** */ { ubi_btNodePtr follower = NULL; int whichway = ubi_trLEFT; while( NULL != leader ) { follower = leader; leader = follower->Link[ whichway ]; if( NULL == leader ) { whichway = ubi_trRevWay( whichway ); leader = follower->Link[ whichway ]; } } return( follower ); } /* ubi_btLeafNode */
ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) /* ------------------------------------------------------------------------ ** * Returns a pointer to a leaf node. * * Input: leader - Pointer to a node at which to start the descent. * * Output: A pointer to a leaf node, selected in a somewhat arbitrary * manner but with an effort to dig deep. * * Notes: I wrote this function because I was using splay trees as a * database cache. The cache had a maximum size on it, and I * needed a way of choosing a node to sacrifice if the cache * became full. In a splay tree, less recently accessed nodes * tend toward the bottom of the tree, meaning that leaf nodes * are good candidates for removal. (I really can't think of * any other reason to use this function.) * + In a simple binary tree, or in an AVL tree, the most recently * added nodes tend to be nearer the bottom, making this a *bad* * way to choose which node to remove from the cache. * + Randomizing the traversal order is probably a good idea. You * can improve the randomization of leaf node selection by passing * in pointers to nodes other than the root node each time. A * pointer to any node in the tree will do. Of course, if you * pass a pointer to a leaf node you'll get the same thing back. * + In an unbalanced splay tree, if you simply traverse downward * until you hit a leaf node it is possible to accidentally * stumble onto a short path. The result will be a leaf node * that is actually very high in the tree--possibly a very * recently accessed node. Not good. This function can follow * multiple paths in an effort to find a leaf node deeper * in the tree. Following a single path, of course, is the * fastest way to find a leaf node. A complete traversal would * be sure to find the deepest leaf but would be very costly in * terms of time. This function uses a compromise that has * worked well in testing. * * ------------------------------------------------------------------------ ** */ { #define MAXPATHS 4 /* Set higher for more maximum paths, lower for fewer. */ ubi_trNodePtr p[MAXPATHS]; ubi_trNodePtr q[MAXPATHS]; int whichway = ubi_trLEFT; int paths; int i, j; /* If the subtree is empty, return NULL. */ if( NULL == leader ) return( NULL ); /* Initialize the p[] array with a pointer to the single node we've been * given as a starting point. */ p[0] = leader; paths = 1; while( paths > 0 ) { for( i = 0; i < paths; i++ ) q[i] = p[i]; for( i = j = 0; (i < paths) && (j < MAXPATHS); i++ ) { if( NULL != q[i]->Link[whichway] ) p[j++] = q[i]->Link[whichway]; whichway = ubi_trRevWay( whichway ); if( (j < MAXPATHS) && (NULL != q[i]->Link[whichway]) ) p[j++] = q[i]->Link[whichway]; } paths = j; } return( q[0] ); } /* ubi_btLeafNode */