An AVL tree can be converted to a "LAT" which is a linked-list-AVL-tree. In this transient form the tree is not a valid AVL tree; this form is used in the Merge operation, and can be created to speed in-order input of large trees. The details of LAT format are not public.
The elements above should be declared in a configuration.h file and included before "avl.h" in any file that makes use of the AVL code {see "avltest.h"}.
AVL *pAVRoot;
or for an array of AVL trees
AVL *sbpAVList[MAXTABLE];
A nil AVL tree is provided as "nilAV", so
AVL *pAVRoot = nilAV;is a legal initialization. The classic C
(AVL *)0
is also a
legal initialization, but might not mean the same thing to the AVL code.
A function "AVInit" can be passed a pointer to an AVL pointer to make this assignment (for compatibility with other MICE routines requiring Init functions). Example:
AVInit(& pAVRoot);
Inserting/Searching in a tree is accomplished by
The function "AEInit" will be called to initialize any new nodes in the tree (if the record already exists "AEInit" is not called); AVpAEInsert is set to the located data (in either case). "AVInsert" returns non-zero if the tree grew. Example:
pKECmp = gets(sbKey); (void) AVInsert(& pAVFile1, 0); AEReport(AVpAEInsert); ...
Deleting from the tree is just as easy :-)
pKECmp = "zap_me"; AVDelete(& pAVRoot);
To scan every node in the tree in order the user can call "AVScan". This function will call a user supplied function on every AE_ELEMENT in tree, or stop when any user function returns non-zero. "AVScan" returns either zero for "not found" or the non-zero return code from some (user) call. Example:
(void) AVScan(pAVRoot, puts)
To reclaim the memory used by a tree (and destroy the tree) the user may call "AVFree" which will recursively delete all nodes in the tree. "AEFree" is called to prepare each AE_ELEMENT node for being free-d. Example:
AVFree(pAVRoot); pAVRoot = nilAV;
The typedef "AVCARDINAL" is used to declare counts of AVL nodes. It is always unsigned, but may be size adjusted for different applications or for machine speed optimization. AVCARDINAL is returned by "AVCount", and is used in the arguments of "AVConstruct" and "AVMerge".
The "AVCount" function returns the number of elements in an AVL tree; this is most useful before a call to "AVConstruct", and even works if the tree is currently "LAT". This is the only AVL routine other than "AVConstruct" that is guaranteed not to drop core if this is true! Example:
printf("%d", AVCount(pAVTemp));
The user should use "AVBegin", "AVEnd", "AVStep" to build an AVL tree
from any pre-sorted input source. "AVBegin" will return non-zero if
any pending in-order input is happening {bug}. "AVStep" will return an
AE_ELEMENT pointer to the next node in the tree, the user should fill
in the key info. "AVEnd" returns the root of the tree and closes the
LAT insertion.
Example:
register AE_ELEMENT *pAE; (void) AVBegin(); while (NULL != gets(sbBuf)) { pAE = AVStep(); MyInit(pAE, sbBuf); } pAVRoot = AVEnd();
For some cases, it is easy to build a 100% efficient AVL tree from a
sorted LAT list; "AVConstruct" does the dirty work of doing this. The
user usually will use "AVBegin", "AVEnd", "AVStep" to do this.
"AVConstruct" is passed a LAT list of AVL nodes, a count of the nodes
it is to build a balanced tree from (type AVCARDINAL), and an address
to hang the new tree from. It returns the the node remaining on the
LAT list (or nilAV). [Some randomness is used to reduce any chance of
a deliberate worst-case tree construction :-)]
Example:
(void) AVConstruct(pAVLat, iCount, & pAVRoot)
The function "AVLat" efficiently turns the bushy AVL tree in a linked-list.
In this form "AVConstruct" can be called to build a perfect
tree. The user will (almost) never call this routine, the only time
it is suggested is when the tree to be re-constructed is going to be
searched many, many times without changing.
Example:
AVCARDINAL n; n = AVCount(pAVRoot); (void) AVLat(pAVRoot, & pAVTemp); (void) AVConstruct(pAVTemp, n, & pAVRoot);
To merge two AVL trees into one (destroying both subtrees) we use
"AVMerge". See "AEMerge" above. AEMerge-s third parameter is a
pointer to an AVCARDINAL. It is used to record the number of elements
in the resulting tree, if it is (AVCARDINAL *)0 it will be ignored.
The first two arguments are the component trees (note that the first
one has "precedence" over the second by MICE convention). The function
"AESame" should be defined to handle return codes of 0 from "AEMerge".
Example:
/* merge pAV_A, pAV_B */ pAV_A = AVMerge(pAV_A, pAV_B, & iCountA) pAV_B = nilAV; iCountB = 0;
If the user believes that the AVL routines have produced an invalid tree "AVVerify" may be called to confirm or deny it. "AVVerify" returns the maximum depth of the tree. If an error is found in the tree "Squeak" will be called with a (char *) to indicate the error:
(char *) | reason for call |
---|---|
AVErrNone | the computed balance factors are impossible |
AVErrLeft | the tree *should be* balanced left (it is not) |
AVErrRight | the tree *should be* balanced right |
AVErrCenter | the tree *should be* balanced exactly |
AVVerify(pAVRoot);
For better debugging an AVL tree may be displayed via "AVPrint"; "AEPrint"
is called to output each nodes name. "-", "/", and "\" are used to display
balance factors. "~" is used to display an empty (sub)tree.
Example:
Output:AVPrint(pAV); putchar('\n');
k=0\(e=1-(c=6,i=3),s=5-(n=4\(~,o=7),v=2/(t=8,~)))
AVL *pAVRoot;
.
$Id: avl.html,v 6.9 2012/08/30 14:53:51 ksb Exp $