942 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			942 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/** <plaintext>
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								* avl.c -- C source file for avl trees. Contains the auxillary routines
							 | 
						||
| 
								 | 
							
								*          and defines for the avl tree functions and user interface and
							 | 
						||
| 
								 | 
							
								*          includes all the necessary public and private routines
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								* Created 03/01/89 by Brad Appleton
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								* ^{Mods:* }
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								* Fri Jul 14 13:53:42 1989, Rev 1.0, brad(0165)
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								_______________________________________________________________________________
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                   LICENSE
							 | 
						||
| 
								 | 
							
								                                   =======
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This software is not subject to any license  of  the  American  Telephone  and
							 | 
						||
| 
								 | 
							
								Telegraph Company or of the Regents of the University of California.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Permission is granted to anyone to use this software for any  purpose  on  any
							 | 
						||
| 
								 | 
							
								computer  system,  and  to alter it and redistribute it freely, subject to the
							 | 
						||
| 
								 | 
							
								following restrictions:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  1.  Neither  the  authors  of  the  software  nor  their   employers
							 | 
						||
| 
								 | 
							
								      (including  any of the employers' subsidiaries and subdivisions)
							 | 
						||
| 
								 | 
							
								      are responsible for maintaining & supporting  this  software  or
							 | 
						||
| 
								 | 
							
								      for any consequences resulting from the use of this software, no
							 | 
						||
| 
								 | 
							
								      matter how awful, even if they arise from flaws in the  software
							 | 
						||
| 
								 | 
							
								      (see LIABILITY).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  2.  The origin of this software must not be  misrepresented,  either
							 | 
						||
| 
								 | 
							
								      by  explicit  claim  or  by omission.  Since few users ever read
							 | 
						||
| 
								 | 
							
								      sources, credits must appear in the documentation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  3.  Altered versions must be plainly marked as such, and must not be
							 | 
						||
| 
								 | 
							
								      misrepresented  as being the original software.  Since few users
							 | 
						||
| 
								 | 
							
								      ever read sources, credits must appear in the documentation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  4.  This notice may not be removed or altered.
							 | 
						||
| 
								 | 
							
								_______________________________________________________________________________
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                NO WARRANTY
							 | 
						||
| 
								 | 
							
								                                ===========
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Because this software is licensed free  of  charge,  we  (the  authors  and/or
							 | 
						||
| 
								 | 
							
								distributors  of  this software) provide absolutely no warranty, to the extent
							 | 
						||
| 
								 | 
							
								permitted by applicable state law.  Except when otherwise stated  in  writing,
							 | 
						||
| 
								 | 
							
								the  authors  and  distributors  of this software and/or other parties provide
							 | 
						||
| 
								 | 
							
								this program "as is"  without  warranty  of  any  kind,  either  expressed  or
							 | 
						||
| 
								 | 
							
								implied,   including,   but   not   limited  to,  the  implied  warranties  of
							 | 
						||
| 
								 | 
							
								merchantability and fitness for a particular purpose.  The entire risk  as  to
							 | 
						||
| 
								 | 
							
								the  quality  and performance of this software lies with the recipients and/or
							 | 
						||
| 
								 | 
							
								users of this software and not with any of the authors and/or distributors  of
							 | 
						||
| 
								 | 
							
								this  software,  nor  with  any  of  their  employers,  including  any  of the
							 | 
						||
| 
								 | 
							
								employers' subsidiaries and subdivisions. Should the program prove  defective,
							 | 
						||
| 
								 | 
							
								the  recipients/users  of  this  software  assume  the  cost  of all necessary
							 | 
						||
| 
								 | 
							
								servicing, repair, or correction.
							 | 
						||
| 
								 | 
							
								_______________________________________________________________________________
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                 LIABILITY
							 | 
						||
| 
								 | 
							
								                                 =========
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In no event  unless  required  by  applicable  law  will  the  authors  and/or
							 | 
						||
| 
								 | 
							
								distributors  of  this  software, their employers, and any subsidiaries and/or
							 | 
						||
| 
								 | 
							
								subdivisions of their employers, and/or any other party who  may  redistribute
							 | 
						||
| 
								 | 
							
								this software as permitted in the LICENSE section of this notice, be liable to
							 | 
						||
| 
								 | 
							
								the recipients/users of this software for damages including any lost  profits,
							 | 
						||
| 
								 | 
							
								lost  monies,  or  other special, incidental, or consequential damages arising
							 | 
						||
| 
								 | 
							
								out of the use or inabilty to use (including but not limited to loss  of  data
							 | 
						||
| 
								 | 
							
								or  data  being  rendered inaccurate or lossed sustained by third parties or a
							 | 
						||
| 
								 | 
							
								failure of the software to operate with any other software or  hardware)  this
							 | 
						||
| 
								 | 
							
								software, even if you have been advised of the possibility of such damages, or
							 | 
						||
| 
								 | 
							
								for any claim by any other party.
							 | 
						||
| 
								 | 
							
								_______________________________________________________________________________
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Heavily  modified  by  Jan  Wielemaker,  wielemak@science.uva.nl.  Brief
							 | 
						||
| 
								 | 
							
								summary:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									- Added prototypes and reformatted the sources.
							 | 
						||
| 
								 | 
							
									- Added includes
							 | 
						||
| 
								 | 
							
									- Swapped various arguments
							 | 
						||
| 
								 | 
							
									- Changes some of the interfaces
							 | 
						||
| 
								 | 
							
									- Added enumeration interface
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     /* some common #defines used throughout most of my files */
							 | 
						||
| 
								 | 
							
								#define  PUBLIC			/* default */
							 | 
						||
| 
								 | 
							
								#define  FALSE    0
							 | 
						||
| 
								 | 
							
								#define  TRUE     !FALSE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     /* some defines for debugging purposes */
							 | 
						||
| 
								 | 
							
								#ifdef NDEBUG
							 | 
						||
| 
								 | 
							
								#define DBG(x)			/* x */
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define DBG(x)          x
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define  NEXTERN		/* dont include "extern" declarations from header files */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								#include "avl.h"		/* public types for avl trees */
							 | 
						||
| 
								 | 
							
								#ifdef __WINDOWS__
							 | 
						||
| 
								 | 
							
								#define inline __inline
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /* MIN and MAX macros (used for rebalancing) */
							 | 
						||
| 
								 | 
							
								#undef MIN
							 | 
						||
| 
								 | 
							
								#undef MAX
							 | 
						||
| 
								 | 
							
								#define  MIN(a,b)    ((a) < (b) ? (a) : (b))
							 | 
						||
| 
								 | 
							
								#define  MAX(a,b)    ((a) > (b) ? (a) : (b))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       Auxillary functions
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       routines to allocate/de-allocate an AVL node,
							 | 
						||
| 
								 | 
							
								*       and determine the type of an AVL node.
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* ckalloc(size) -- allocate space; check for success */
							 | 
						||
| 
								 | 
							
								static void *
							 | 
						||
| 
								 | 
							
								ckalloc(size_t size)
							 | 
						||
| 
								 | 
							
								{ void *ptr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( !(ptr = malloc(size)) )
							 | 
						||
| 
								 | 
							
								  { fprintf(stderr, "Unable to allocate storage.");
							 | 
						||
| 
								 | 
							
								    exit(1);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ptr;
							 | 
						||
| 
								 | 
							
								}				/* ckalloc */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define sizeofnode(size) ((size_t)&((AVLtree)0)->data[0] + size)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* new_node() -- get space for a new node and its data;
							 | 
						||
| 
								 | 
							
								*               return the address of the new node
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static AVLtree
							 | 
						||
| 
								 | 
							
								new_node(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ AVLtree root;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( tree->alloc )
							 | 
						||
| 
								 | 
							
								    root = (*tree->alloc)(tree->client_data, sizeofnode(tree->isize));
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    root = ckalloc(sizeofnode(tree->isize));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  memcpy(root->data, data, tree->isize);
							 | 
						||
| 
								 | 
							
								  root->bal = BALANCED;
							 | 
						||
| 
								 | 
							
								  root->subtree[LEFT] = root->subtree[RIGHT] = NULL_TREE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return root;
							 | 
						||
| 
								 | 
							
								}				/* new_node */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* free_node()  --  free space for a node and its data!
							 | 
						||
| 
								 | 
							
								*                  reset the node pointer to NULL
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								free_node(AVL_TREE tree, AVLtree *rootp)
							 | 
						||
| 
								 | 
							
								{ AVLtree root = *rootp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( tree->destroy )
							 | 
						||
| 
								 | 
							
								    (*tree->destroy)(root->data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( tree->free )
							 | 
						||
| 
								 | 
							
								    (*tree->free)(tree->client_data, root, sizeofnode(tree->isize));
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    free(root);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  *rootp = NULL_TREE;
							 | 
						||
| 
								 | 
							
								}				/* free_node */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* node_type() -- determine the number of null pointers for a given
							 | 
						||
| 
								 | 
							
								*                node in an AVL tree, Returns a value of type NODE
							 | 
						||
| 
								 | 
							
								*                which is an enumeration type with the following values:
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*                  IS_TREE     --  both subtrees are non-empty
							 | 
						||
| 
								 | 
							
								*                  IS_LBRANCH  --  left subtree is non-empty; right is empty
							 | 
						||
| 
								 | 
							
								*                  IS_RBRANCH  --  right subtree is non-empty; left is empty
							 | 
						||
| 
								 | 
							
								*                  IS_LEAF     --  both subtrees are empty
							 | 
						||
| 
								 | 
							
								*                  IS_NULL     --  given tree is empty
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static NODE
							 | 
						||
| 
								 | 
							
								node_type(AVLtree tree)
							 | 
						||
| 
								 | 
							
								{ if (tree == NULL_TREE)
							 | 
						||
| 
								 | 
							
								  { return IS_NULL;
							 | 
						||
| 
								 | 
							
								  } else if ((tree->subtree[LEFT] != NULL_TREE) &&
							 | 
						||
| 
								 | 
							
									     (tree->subtree[RIGHT] != NULL_TREE))
							 | 
						||
| 
								 | 
							
								  { return IS_TREE;
							 | 
						||
| 
								 | 
							
								  } else if (tree->subtree[LEFT] != NULL_TREE)
							 | 
						||
| 
								 | 
							
								  { return IS_LBRANCH;
							 | 
						||
| 
								 | 
							
								  } else if (tree->subtree[RIGHT] != NULL_TREE)
							 | 
						||
| 
								 | 
							
								  { return IS_RBRANCH;
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  { return IS_LEAF;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}				/* node_type */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       static functions for manipulating AVL trees
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*  This following defines a set of routines for creating, maintaining, and
							 | 
						||
| 
								 | 
							
								*  manipulating AVL Trees as an Abtract Data Type. The routines in this
							 | 
						||
| 
								 | 
							
								*  file that are accessible (through the avl tree user-interface) to other
							 | 
						||
| 
								 | 
							
								*  files to allow other programmers to:
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   Insert, Delete, and Find a given data item from a Tree.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   Delete and Find the minimal and Maximal items in a Tree.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   Walk through every node in a tree performing a giving operation.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   Walk through and free up space for every node in a tree while performing
							 | 
						||
| 
								 | 
							
								*   a given operation on the data items as they are encountered.
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       routines used to find the minimal and maximal elements
							 | 
						||
| 
								 | 
							
								*       (nodes) of an AVL tree.
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_min() -- compare function used to find the minimal element in a tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								avl_min(void *elt1, void *elt2, NODE nd_typ)
							 | 
						||
| 
								 | 
							
								{ return (nd_typ == IS_RBRANCH || nd_typ == IS_LEAF)
							 | 
						||
| 
								 | 
							
									 ? 0	/* left subtree is empty -- this is the minimum */
							 | 
						||
| 
								 | 
							
									 : -1;			/* keep going left */
							 | 
						||
| 
								 | 
							
								}				/* avl_min */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_max() -- compare function used to find the maximal element in a tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								avl_max(void *elt1, void *elt2, NODE nd_typ)
							 | 
						||
| 
								 | 
							
								{ return (nd_typ == IS_LBRANCH || nd_typ == IS_LEAF)
							 | 
						||
| 
								 | 
							
									? 0	/* right subtree is empty -- this is the maximum */
							 | 
						||
| 
								 | 
							
									: 1;			/* keep going right */
							 | 
						||
| 
								 | 
							
								}				/* avl_max */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       Routines to perform rotations on AVL trees
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* rotate_once()  --  rotate a given node in the given direction
							 | 
						||
| 
								 | 
							
								*                    to restore the balance of a tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static short
							 | 
						||
| 
								 | 
							
								rotate_once(AVLtree * rootp, DIRECTION dir)
							 | 
						||
| 
								 | 
							
								{ DIRECTION other_dir = OPPOSITE(dir);	/* opposite direction to "dir" */
							 | 
						||
| 
								 | 
							
								  AVLtree old_root = *rootp;	/* copy of original root of tree */
							 | 
						||
| 
								 | 
							
								  short ht_unchanged;		/* true if height unchanged */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ht_unchanged = ((*rootp)->subtree[other_dir]->bal) ? FALSE : TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* assign new root */
							 | 
						||
| 
								 | 
							
								  *rootp = old_root->subtree[other_dir];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* new-root exchanges it's "dir" subtree for it's parent */
							 | 
						||
| 
								 | 
							
								  old_root->subtree[other_dir] = (*rootp)->subtree[dir];
							 | 
						||
| 
								 | 
							
								  (*rootp)->subtree[dir] = old_root;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* update balances */
							 | 
						||
| 
								 | 
							
								  old_root->bal = -(dir == LEFT ? --((*rootp)->bal) : ++((*rootp)->bal));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ht_unchanged;
							 | 
						||
| 
								 | 
							
								}				/* rotate_once */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* rotate_twice()  --  rotate a given node in the given direction
							 | 
						||
| 
								 | 
							
								*                     and then in the opposite direction
							 | 
						||
| 
								 | 
							
								*                     to restore the balance of a tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								rotate_twice(AVLtree * rootp, DIRECTION dir)
							 | 
						||
| 
								 | 
							
								{ DIRECTION other_dir = OPPOSITE(dir);
							 | 
						||
| 
								 | 
							
								  AVLtree old_root = *rootp;
							 | 
						||
| 
								 | 
							
								  AVLtree old_other_dir_subtree = (*rootp)->subtree[other_dir];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* assign new root */
							 | 
						||
| 
								 | 
							
								  *rootp = old_root->subtree[other_dir]->subtree[dir];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* new-root exchanges it's "dir" subtree for it's grandparent */
							 | 
						||
| 
								 | 
							
								  old_root->subtree[other_dir] = (*rootp)->subtree[dir];
							 | 
						||
| 
								 | 
							
								  (*rootp)->subtree[dir] = old_root;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* new-root exchanges it's "other-dir" subtree for it's parent */
							 | 
						||
| 
								 | 
							
								  old_other_dir_subtree->subtree[dir] = (*rootp)->subtree[other_dir];
							 | 
						||
| 
								 | 
							
								  (*rootp)->subtree[other_dir] = old_other_dir_subtree;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* update balances */
							 | 
						||
| 
								 | 
							
								  (*rootp)->subtree[LEFT]->bal = -MAX((*rootp)->bal, 0);
							 | 
						||
| 
								 | 
							
								  (*rootp)->subtree[RIGHT]->bal = -MIN((*rootp)->bal, 0);
							 | 
						||
| 
								 | 
							
								  (*rootp)->bal = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}				/* rotate_twice */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*                       Rebalance an AVL tree
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* balance()  --  determines and performs the  sequence of rotations needed
							 | 
						||
| 
								 | 
							
								*                   (if any) to restore the balance of a given tree.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*     Returns 1 if tree height changed due to rotation; 0 otherwise
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static short
							 | 
						||
| 
								 | 
							
								balance(AVLtree * rootp)
							 | 
						||
| 
								 | 
							
								{ short special_case = FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (LEFT_IMBALANCE(*rootp))
							 | 
						||
| 
								 | 
							
								  {				/* need a right rotation */
							 | 
						||
| 
								 | 
							
								    if ((*rootp)->subtree[LEFT]->bal == RIGHT_HEAVY)
							 | 
						||
| 
								 | 
							
								    { rotate_twice(rootp, RIGHT);	/* double RL rotation needed */
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    {				/* single RR rotation needed */
							 | 
						||
| 
								 | 
							
								      special_case = rotate_once(rootp, RIGHT);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else if (RIGHT_IMBALANCE(*rootp))
							 | 
						||
| 
								 | 
							
								  {				/* need a left rotation */
							 | 
						||
| 
								 | 
							
								    if ((*rootp)->subtree[RIGHT]->bal == LEFT_HEAVY)
							 | 
						||
| 
								 | 
							
								    { rotate_twice(rootp, LEFT);	/* double LR rotation needed */
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    {				/* single LL rotation needed */
							 | 
						||
| 
								 | 
							
								      special_case = rotate_once(rootp, LEFT);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  { return HEIGHT_UNCHANGED;	/* no rotation occurred */
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (special_case) ? HEIGHT_UNCHANGED : HEIGHT_CHANGED;
							 | 
						||
| 
								 | 
							
								}				/* balance */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       Routines to:    Find an item in an AVL tree
							 | 
						||
| 
								 | 
							
								*                       Insert an item into an AVL tree
							 | 
						||
| 
								 | 
							
								*                       Delete an item from an AVL tree
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_find() -- find an item in the given tree
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   PARAMETERS:
							 | 
						||
| 
								 | 
							
								*                data       --  a pointer to the key to find
							 | 
						||
| 
								 | 
							
								*                rootp      --  a pointer to an AVL tree
							 | 
						||
| 
								 | 
							
								*                compar     --  name of a function to compare 2 data items
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static void *
							 | 
						||
| 
								 | 
							
								avl_find(void *data, AVLtree tree, int (*compar) (void *l, void *r, NODE))
							 | 
						||
| 
								 | 
							
								{ NODE nd_typ = node_type(tree);
							 | 
						||
| 
								 | 
							
								  int cmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while ((tree != NULL_TREE) &&
							 | 
						||
| 
								 | 
							
									 (cmp = (*compar)(data, tree->data, nd_typ)))
							 | 
						||
| 
								 | 
							
								  { tree = tree->subtree[(cmp < 0) ? LEFT : RIGHT];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (tree == NULL_TREE) ? NULL : tree->data;
							 | 
						||
| 
								 | 
							
								}				/* avl_find */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_insert() -- insert an item into the given tree
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   PARAMETERS:
							 | 
						||
| 
								 | 
							
								*                data       --  a pointer to a pointer to the data to add;
							 | 
						||
| 
								 | 
							
								*                               On exit, *data is NULL if insertion succeeded,
							 | 
						||
| 
								 | 
							
								*                               otherwise address of the duplicate key
							 | 
						||
| 
								 | 
							
								*                rootp      --  a pointer to an AVL tree
							 | 
						||
| 
								 | 
							
								*                compar     --  name of the function to compare 2 data items
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static short
							 | 
						||
| 
								 | 
							
								avl_insert(AVL_TREE tree, AVLtree *rootp, void **data)
							 | 
						||
| 
								 | 
							
								{ short increase;
							 | 
						||
| 
								 | 
							
								  int cmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (*rootp == NULL_TREE)
							 | 
						||
| 
								 | 
							
								  {				/* insert new node here */
							 | 
						||
| 
								 | 
							
								    *rootp = new_node(tree, *data);
							 | 
						||
| 
								 | 
							
								    *data = NULL;		/* set return value in data */
							 | 
						||
| 
								 | 
							
								    return HEIGHT_CHANGED;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cmp = (*tree->compar)(*data, (*rootp)->data, IS_NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (cmp < 0)
							 | 
						||
| 
								 | 
							
								  {				/* insert into the left subtree */
							 | 
						||
| 
								 | 
							
								    increase = -avl_insert(tree, &((*rootp)->subtree[LEFT]), data);
							 | 
						||
| 
								 | 
							
								    if (*data != NULL)
							 | 
						||
| 
								 | 
							
								      return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  } else if (cmp > 0)
							 | 
						||
| 
								 | 
							
								  {				/* insert into the right subtree */
							 | 
						||
| 
								 | 
							
								    increase = avl_insert(tree, &((*rootp)->subtree[RIGHT]), data);
							 | 
						||
| 
								 | 
							
								    if (*data != NULL)
							 | 
						||
| 
								 | 
							
								      return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  {				/* data already exists */
							 | 
						||
| 
								 | 
							
								    *data = (*rootp)->data;	/* set return value in data */
							 | 
						||
| 
								 | 
							
								    return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  (*rootp)->bal += increase;	/* update balance factor */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /************************************************************************
							 | 
						||
| 
								 | 
							
								  * re-balance if needed -- height of current tree increases only if its
							 | 
						||
| 
								 | 
							
								  * subtree height increases and the current tree needs no rotation.
							 | 
						||
| 
								 | 
							
								  ************************************************************************/
							 | 
						||
| 
								 | 
							
								  return (increase && (*rootp)->bal)
							 | 
						||
| 
								 | 
							
									? (1 - balance(rootp))
							 | 
						||
| 
								 | 
							
									: HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								}				/* avl_insert */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								memswap(void *p1, void *p2, size_t size)
							 | 
						||
| 
								 | 
							
								{ char *s1 = p1;
							 | 
						||
| 
								 | 
							
								  char *s2 = p2;
							 | 
						||
| 
								 | 
							
								  char buf[256];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while(size > 0)
							 | 
						||
| 
								 | 
							
								  { size_t bytes = (size > sizeof(buf) ? sizeof(buf) : size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    memcpy(buf, s1, bytes);
							 | 
						||
| 
								 | 
							
								    memcpy(s1, s2, bytes);
							 | 
						||
| 
								 | 
							
								    memcpy(s2, buf, bytes);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    s1 += bytes;
							 | 
						||
| 
								 | 
							
								    s2 += bytes;
							 | 
						||
| 
								 | 
							
								    size -= bytes;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_delete() -- delete an item from the given tree
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   PARAMETERS:
							 | 
						||
| 
								 | 
							
								*                data       --  a pointer to a pointer to the key to delete
							 | 
						||
| 
								 | 
							
								*                               On exit, *data points to the deleted data item
							 | 
						||
| 
								 | 
							
								*                               (or NULL if deletion failed).
							 | 
						||
| 
								 | 
							
								*                rootp      --  a pointer to an AVL tree
							 | 
						||
| 
								 | 
							
								*                compar     --  name of function to compare 2 data items
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static short
							 | 
						||
| 
								 | 
							
								avl_delete(AVL_TREE tree, AVLtree *rootp, void *data, int *found,
							 | 
						||
| 
								 | 
							
									   int (*compar)(void*, void*, NODE))
							 | 
						||
| 
								 | 
							
								{ short decrease;
							 | 
						||
| 
								 | 
							
								  int cmp;
							 | 
						||
| 
								 | 
							
								  AVLtree old_root = *rootp;
							 | 
						||
| 
								 | 
							
								  NODE nd_typ = node_type(*rootp);
							 | 
						||
| 
								 | 
							
								  DIRECTION dir = (nd_typ == IS_LBRANCH) ? LEFT : RIGHT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (*rootp == NULL_TREE)
							 | 
						||
| 
								 | 
							
								  { 				/* data not found */
							 | 
						||
| 
								 | 
							
								    if ( found )
							 | 
						||
| 
								 | 
							
								      *found = FALSE;
							 | 
						||
| 
								 | 
							
								    return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cmp = (*compar)(data, (*rootp)->data, nd_typ);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (cmp < 0)
							 | 
						||
| 
								 | 
							
								  {				/* delete from left subtree */
							 | 
						||
| 
								 | 
							
								    decrease = -avl_delete(tree, &((*rootp)->subtree[LEFT]), data, found, compar);
							 | 
						||
| 
								 | 
							
								    if ( found && *found == FALSE )
							 | 
						||
| 
								 | 
							
								      return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  } else if (cmp > 0)
							 | 
						||
| 
								 | 
							
								  {				/* delete from right subtree */
							 | 
						||
| 
								 | 
							
								    decrease = avl_delete(tree, &((*rootp)->subtree[RIGHT]), data, found, compar);
							 | 
						||
| 
								 | 
							
								    if ( found && *found == FALSE )
							 | 
						||
| 
								 | 
							
								      return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  {				/* cmp == 0 */
							 | 
						||
| 
								 | 
							
								    decrease = 0;		/* JW: Silence compiler */
							 | 
						||
| 
								 | 
							
								    if ( found )
							 | 
						||
| 
								 | 
							
								      *found = TRUE;
							 | 
						||
| 
								 | 
							
								    if ( data && data != (*rootp)->data )
							 | 
						||
| 
								 | 
							
								    { if ( found )
							 | 
						||
| 
								 | 
							
									memcpy(data, (*rootp)->data, tree->isize);
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
									memswap(data, (*rootp)->data, tree->isize);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      /***********************************************************************
							 | 
						||
| 
								 | 
							
								      *  At this point we know "cmp" is zero and "*rootp" points to
							 | 
						||
| 
								 | 
							
								      *  the node that we need to delete.  There are three cases:
							 | 
						||
| 
								 | 
							
								      *
							 | 
						||
| 
								 | 
							
								      *     1) The node is a leaf.  Remove it and return.
							 | 
						||
| 
								 | 
							
								      *
							 | 
						||
| 
								 | 
							
								      *     2) The node is a branch (has only 1 child). Make "*rootp"
							 | 
						||
| 
								 | 
							
								      *        (the pointer to this node) point to the child.
							 | 
						||
| 
								 | 
							
								      *
							 | 
						||
| 
								 | 
							
								      *     3) The node has two children. We swap data with the successor of
							 | 
						||
| 
								 | 
							
								      *        "*rootp" (the smallest item in its right subtree) and delete
							 | 
						||
| 
								 | 
							
								      *        the successor from the right subtree of "*rootp".  The
							 | 
						||
| 
								 | 
							
								      *        identifier "decrease" should be reset if the subtree height
							 | 
						||
| 
								 | 
							
								      *        decreased due to the deletion of the successor of "rootp".
							 | 
						||
| 
								 | 
							
								      ***********************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (nd_typ)
							 | 
						||
| 
								 | 
							
								    {				/* what kind of node are we removing? */
							 | 
						||
| 
								 | 
							
								      case IS_LEAF:
							 | 
						||
| 
								 | 
							
									free_node(tree, rootp);	/* free the leaf, its height     */
							 | 
						||
| 
								 | 
							
									return HEIGHT_CHANGED;	/* changes from 1 to 0, return 1 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      case IS_RBRANCH:		/* only child becomes new root */
							 | 
						||
| 
								 | 
							
								      case IS_LBRANCH:
							 | 
						||
| 
								 | 
							
									*rootp = (*rootp)->subtree[dir];
							 | 
						||
| 
								 | 
							
									free_node(tree, &old_root);	/* free the deleted node */
							 | 
						||
| 
								 | 
							
									return HEIGHT_CHANGED;	/* we just shortened the "dir" subtree */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      case IS_TREE:
							 | 
						||
| 
								 | 
							
									decrease = avl_delete(tree,
							 | 
						||
| 
								 | 
							
											      &((*rootp)->subtree[RIGHT]),
							 | 
						||
| 
								 | 
							
											      (*rootp)->data, NULL,
							 | 
						||
| 
								 | 
							
											      avl_min);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case IS_NULL:		/* JW: Silence compiler.  Cannot happen */
							 | 
						||
| 
								 | 
							
									assert(0);
							 | 
						||
| 
								 | 
							
									break;
							 | 
						||
| 
								 | 
							
								    }				/* switch */
							 | 
						||
| 
								 | 
							
								  }				/* else */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  (*rootp)->bal -= decrease;	/* update balance factor */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /**********************************************************************
							 | 
						||
| 
								 | 
							
								  * Rebalance if necessary -- the height of current tree changes if one
							 | 
						||
| 
								 | 
							
								  * of two things happens: (1) a rotation was performed which changed
							 | 
						||
| 
								 | 
							
								  * the height of the subtree (2) the subtree height decreased and now
							 | 
						||
| 
								 | 
							
								  * matches the height of its other subtree (so the current tree now
							 | 
						||
| 
								 | 
							
								  * has a zero balance when it previously did not).
							 | 
						||
| 
								 | 
							
								  **********************************************************************/
							 | 
						||
| 
								 | 
							
								  if (decrease && (*rootp)->bal)
							 | 
						||
| 
								 | 
							
								  { return balance(rootp);	/* rebalance and see if height changed */
							 | 
						||
| 
								 | 
							
								  } else if (decrease && !(*rootp)->bal)
							 | 
						||
| 
								 | 
							
								  { return HEIGHT_CHANGED;	/* balanced because subtree decreased */
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  { return HEIGHT_UNCHANGED;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}				/* avl_delete */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								*       Routines which Recursively Traverse an AVL TREE
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								* These routines may perform a particular action function upon each node
							 | 
						||
| 
								 | 
							
								* encountered. In these cases, "action" has the following definition:
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*   void action(data, order, node, level, bal)
							 | 
						||
| 
								 | 
							
								*       void   *data
							 | 
						||
| 
								 | 
							
								*       VISIT   order;
							 | 
						||
| 
								 | 
							
								*       NODE    node;
							 | 
						||
| 
								 | 
							
								*       short   bal;
							 | 
						||
| 
								 | 
							
								*       int     level;
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*         "data"    is a pointer to the data field of an AVL node
							 | 
						||
| 
								 | 
							
								*         "order"   corresponds to whether this is the 1st, 2nd or 3rd time
							 | 
						||
| 
								 | 
							
								*                   that this node has been visited.
							 | 
						||
| 
								 | 
							
								*         "node"    indicates which children (if any) of the current node
							 | 
						||
| 
								 | 
							
								*                   are null.
							 | 
						||
| 
								 | 
							
								*         "level"   is the current level (or depth) in the tree of the
							 | 
						||
| 
								 | 
							
								*                   curent node.
							 | 
						||
| 
								 | 
							
								*         "bal"     is the balance factor of the current node.
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/************************************************************************
							 | 
						||
| 
								 | 
							
								*       Walk an AVL tree, performing a given function at each node
							 | 
						||
| 
								 | 
							
								************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_walk -- traverse the given tree performing "action"
							 | 
						||
| 
								 | 
							
								*            upon each data item encountered.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								avl_walk(AVLtree tree, void (*action)(void *data,
							 | 
						||
| 
								 | 
							
												      SIBLING_ORDER order,
							 | 
						||
| 
								 | 
							
												      NODE type,
							 | 
						||
| 
								 | 
							
												      int level,
							 | 
						||
| 
								 | 
							
												      int balance),
							 | 
						||
| 
								 | 
							
									 SIBLING_ORDER sibling_order, int level)
							 | 
						||
| 
								 | 
							
								{ DIRECTION dir1 = (sibling_order == LEFT_TO_RIGHT) ? LEFT : RIGHT;
							 | 
						||
| 
								 | 
							
								  DIRECTION dir2 = OPPOSITE(dir1);
							 | 
						||
| 
								 | 
							
								  NODE node = node_type(tree);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( tree && action )
							 | 
						||
| 
								 | 
							
								  { (*action) (tree->data, PREORDER, node, level, (int)tree->bal);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (tree->subtree[dir1] != NULL_TREE)
							 | 
						||
| 
								 | 
							
								    { avl_walk(tree->subtree[dir1], action, sibling_order, level + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    (*action) (tree->data, INORDER, node, level, (int)tree->bal);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (tree->subtree[dir2] != NULL_TREE)
							 | 
						||
| 
								 | 
							
								    { avl_walk(tree->subtree[dir2], action, sibling_order, level + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    (*action) (tree->data, POSTORDER, node, level, (int)tree->bal);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  /* if non-empty tree */
							 | 
						||
| 
								 | 
							
								}				/* avl_walk */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avl_free() -- free up space for all nodes in a given tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								avl_free(AVL_TREE tree, AVLtree *rootp)
							 | 
						||
| 
								 | 
							
								{ if ( *rootp )
							 | 
						||
| 
								 | 
							
								  { if ( (*rootp)->subtree[LEFT] != NULL_TREE )
							 | 
						||
| 
								 | 
							
								      avl_free(tree, &(*rootp)->subtree[LEFT]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( (*rootp)->subtree[RIGHT] != NULL_TREE )
							 | 
						||
| 
								 | 
							
								      avl_free(tree, &(*rootp)->subtree[RIGHT]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    free_node(tree, rootp);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *    ENUMERATION INTERFACE	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								avlfindfirst()
							 | 
						||
| 
								 | 
							
								avlfindnext()
							 | 
						||
| 
								 | 
							
								avlfinddestroy()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This interface allows for  enumerating  all   elements  in  a key-range.
							 | 
						||
| 
								 | 
							
								avl_find_ge() finds the first node whose  key   is  larger or equal to a
							 | 
						||
| 
								 | 
							
								given  key.  avlfindnext()  returns  the    next  node.  avlfinddestroy()
							 | 
						||
| 
								 | 
							
								destroyes memory allocated for the enum (if any).
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static inline AVLtree
							 | 
						||
| 
								 | 
							
								push_node(avl_enum *e, AVLtree node)
							 | 
						||
| 
								 | 
							
								{ e->parents[e->current++] = node;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return node;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static inline AVLtree
							 | 
						||
| 
								 | 
							
								pop_node(avl_enum *e)
							 | 
						||
| 
								 | 
							
								{ if ( --e->current >= 0 )
							 | 
						||
| 
								 | 
							
								    return e->parents[e->current];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static inline AVLtree
							 | 
						||
| 
								 | 
							
								current_node(avl_enum *e)
							 | 
						||
| 
								 | 
							
								{ if ( e->current >= 1 )
							 | 
						||
| 
								 | 
							
								    return e->parents[e->current-1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void *
							 | 
						||
| 
								 | 
							
								avlfindfirst(AVL_TREE tree, void *data, avl_enum *e)
							 | 
						||
| 
								 | 
							
								{ AVLtree node = tree->root;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( !node )
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  e->tree    = tree;
							 | 
						||
| 
								 | 
							
								  e->current = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for(;;)
							 | 
						||
| 
								 | 
							
								  { int diff;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( data )
							 | 
						||
| 
								 | 
							
								      diff = (*tree->compar)(data, node->data, IS_NULL);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								      diff = -1;			/* search first node */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( diff < 0 )
							 | 
						||
| 
								 | 
							
								    { push_node(e, node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ( node->subtree[LEFT] )
							 | 
						||
| 
								 | 
							
								      { node = node->subtree[LEFT];
							 | 
						||
| 
								 | 
							
								      } else
							 | 
						||
| 
								 | 
							
								      { return node->data;		/* key > target */
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } else if ( diff > 0 )
							 | 
						||
| 
								 | 
							
								    { if ( node->subtree[RIGHT] )
							 | 
						||
| 
								 | 
							
								      { node = node->subtree[RIGHT];
							 | 
						||
| 
								 | 
							
								      } else
							 | 
						||
| 
								 | 
							
								      { if ( (node = current_node(e)) )
							 | 
						||
| 
								 | 
							
									  return node->data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return NULL;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { return push_node(e, node)->data;	/* equal hit */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								Last pushed node is  the  node  returned.   All  nodes  to  the left are
							 | 
						||
| 
								 | 
							
								considered `done'. We must return all nodes   to  the right, followed by
							 | 
						||
| 
								 | 
							
								the parent.
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void *
							 | 
						||
| 
								 | 
							
								avlfindnext(avl_enum *e)
							 | 
						||
| 
								 | 
							
								{ AVLtree n = pop_node(e);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( n->subtree[RIGHT] )
							 | 
						||
| 
								 | 
							
								  { n = push_node(e, n->subtree[RIGHT]);
							 | 
						||
| 
								 | 
							
								    while(n->subtree[LEFT])
							 | 
						||
| 
								 | 
							
								      n = push_node(e, n->subtree[LEFT]);
							 | 
						||
| 
								 | 
							
								    return n->data;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  n = current_node(e);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return n ? n->data : NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								avlfinddestroy(avl_enum *e)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**********************************************************************
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*               C-interface (public functions) for avl trees
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       These are the functions that are visible to the user of the
							 | 
						||
| 
								 | 
							
								*       AVL Tree Library. Mostly they just return or modify a
							 | 
						||
| 
								 | 
							
								*       particular attribute, or Call a private functions with the
							 | 
						||
| 
								 | 
							
								*       given parameters.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       Note that public routine names begin with "avl" whereas
							 | 
						||
| 
								 | 
							
								*       private routine names that are called by public routines
							 | 
						||
| 
								 | 
							
								*       begin with "avl_" (the underscore character is added).
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       Each public routine must convert (cast) any argument of the
							 | 
						||
| 
								 | 
							
								*       public type "AVL_TREE" to a pointer to on object of the
							 | 
						||
| 
								 | 
							
								*       private type "AVLdescriptor" before passing the actual
							 | 
						||
| 
								 | 
							
								*       AVL tree to any of the private routines. In this way, the
							 | 
						||
| 
								 | 
							
								*       type "AVL_TREE" is implemented as an opaque type.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       An "AVLdescriptor" is merely a container for AVL-tree
							 | 
						||
| 
								 | 
							
								*       objects which contains the pointer to the root of the
							 | 
						||
| 
								 | 
							
								*       tree and the various attributes of the tree.
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								*       The function types prototypes for the routines which follow
							 | 
						||
| 
								 | 
							
								*       are declared in the include file "avl.h"
							 | 
						||
| 
								 | 
							
								*
							 | 
						||
| 
								 | 
							
								***********************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlinit() -- get space for an AVL descriptor for the given tree
							 | 
						||
| 
								 | 
							
								*              structure and initialize its fields.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC AVL_TREE
							 | 
						||
| 
								 | 
							
								avlinit(AVL_TREE tree,
							 | 
						||
| 
								 | 
							
									void *cdata, size_t isize,
							 | 
						||
| 
								 | 
							
									int (*compare)(void *l, void*r, NODE type),
							 | 
						||
| 
								 | 
							
									void (*destroy)(void *data),
							 | 
						||
| 
								 | 
							
									void* (*alloc)(void *cdata, size_t bytes),
							 | 
						||
| 
								 | 
							
									void (*free)(void *cdata, void *data, size_t bytes))
							 | 
						||
| 
								 | 
							
								{ tree->root = NULL_TREE;
							 | 
						||
| 
								 | 
							
								  tree->compar = compare;
							 | 
						||
| 
								 | 
							
								  tree->destroy = destroy;
							 | 
						||
| 
								 | 
							
								  tree->alloc = alloc;
							 | 
						||
| 
								 | 
							
								  tree->free = free;
							 | 
						||
| 
								 | 
							
								  tree->isize = (int)isize;
							 | 
						||
| 
								 | 
							
								  tree->client_data = cdata;
							 | 
						||
| 
								 | 
							
								  tree->count = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (AVL_TREE) tree;
							 | 
						||
| 
								 | 
							
								}				/* avlinit */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avldispose() -- free up all space associated with the given tree structure.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void
							 | 
						||
| 
								 | 
							
								avlfree(AVL_TREE tree)
							 | 
						||
| 
								 | 
							
								{ avl_free(tree, &(tree->root));
							 | 
						||
| 
								 | 
							
								}				/* avldispose */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlwalk() -- traverse the given tree structure and perform the
							 | 
						||
| 
								 | 
							
								*              given action on each data item in the tree.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void
							 | 
						||
| 
								 | 
							
								avlwalk(AVL_TREE tree,
							 | 
						||
| 
								 | 
							
									void (*action)(void *data,
							 | 
						||
| 
								 | 
							
										       SIBLING_ORDER order,
							 | 
						||
| 
								 | 
							
										       NODE type,
							 | 
						||
| 
								 | 
							
										       int level,
							 | 
						||
| 
								 | 
							
										       int balance),
							 | 
						||
| 
								 | 
							
									SIBLING_ORDER sibling_order)
							 | 
						||
| 
								 | 
							
								{ avl_walk(tree->root, action, sibling_order, 1);
							 | 
						||
| 
								 | 
							
								}				/* avlwalk */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlcount() --  return the number of nodes in the given tree
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC int
							 | 
						||
| 
								 | 
							
								avlcount(AVL_TREE tree)
							 | 
						||
| 
								 | 
							
								{ return tree->count;
							 | 
						||
| 
								 | 
							
								}				/* avlcount */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlins() -- insert the given item into the tree structure
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void *
							 | 
						||
| 
								 | 
							
								avlins(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ avl_insert(tree, &tree->root, &data);
							 | 
						||
| 
								 | 
							
								  if ( data == NULL )
							 | 
						||
| 
								 | 
							
								    tree->count++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}				/* avlins */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avldel() -- delete the given item from the given tree structure
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC int
							 | 
						||
| 
								 | 
							
								avldel(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ int found;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  avl_delete(tree, &tree->root, data, &found, tree->compar);
							 | 
						||
| 
								 | 
							
								  if ( found )
							 | 
						||
| 
								 | 
							
								    tree->count--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return found;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlfind() -- find the given item in the given tree structure
							 | 
						||
| 
								 | 
							
								*              and return its address (NULL if not found).
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void *
							 | 
						||
| 
								 | 
							
								avlfind(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ return avl_find(data, tree->root, tree->compar);
							 | 
						||
| 
								 | 
							
								}				/* avlfind */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avldelmin() -- delete the minimal item from the given tree structure
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC int
							 | 
						||
| 
								 | 
							
								avldelmin(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ int found;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  avl_delete(tree, &tree->root, data, &found, avl_min);
							 | 
						||
| 
								 | 
							
								  if ( found )
							 | 
						||
| 
								 | 
							
								    tree->count--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return found;
							 | 
						||
| 
								 | 
							
								}				/* avldelmin */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlfindmin() -- find the minimal item in the given tree structure
							 | 
						||
| 
								 | 
							
								*              and return its address (NULL if not found).
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void *
							 | 
						||
| 
								 | 
							
								avlfindmin(AVL_TREE tree)
							 | 
						||
| 
								 | 
							
								{ return avl_find(NULL, tree->root, avl_min);
							 | 
						||
| 
								 | 
							
								}				/* avlfindmin */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avldelmax() -- delete the maximal item from the given tree structure
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC int
							 | 
						||
| 
								 | 
							
								avldelmax(AVL_TREE tree, void *data)
							 | 
						||
| 
								 | 
							
								{ int found;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  avl_delete(tree, &tree->root, data, &found, avl_max);
							 | 
						||
| 
								 | 
							
								  if ( found )
							 | 
						||
| 
								 | 
							
								    tree->count--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return found;
							 | 
						||
| 
								 | 
							
								}				/* avldelmax */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								* avlfindmax() -- find the maximal item in the given tree structure
							 | 
						||
| 
								 | 
							
								*              and return its address (NULL if not found).
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								PUBLIC void *
							 | 
						||
| 
								 | 
							
								avlfindmax(AVL_TREE tree)
							 | 
						||
| 
								 | 
							
								{ return avl_find(NULL, tree->root, avl_max);
							 | 
						||
| 
								 | 
							
								}				/* avlfindmax */
							 |