/** \ingroup lub \defgroup lub_bintree bintree @{ \brief This interface provides a facility which enables a client to order and access a set of arbitary data in a binary "tree" Each "tree" is defined by a number of "clientnodes" which are ordered according to a client defined "key". A "clientkey" is a client specific entity which can be compared with a "clientnode" to determine which is the "greatest". In order to do this the client needs provide a comparison function for comparing a "clientnode" with a "clientkey", and a function to convert a "clientnode" into a "clientkey". The client is responsible for providing each "clientnode" in a tree. This will typically contain some client specific data, but will also need to contain a bintree "node" which is used to structurally relate each node to one another in the tree. A specific "node" may only belong to one tree at a time, but an individual "clientnode" may contain multiple of these if necessary. \par Implementation The implementation of this interface uses a top-down splaying algorithm. \par "Splay trees", or "self-adjusting search trees" are a simple and efficient data structure for storing an ordered set. The data structure consists of a binary tree, without parent pointers, and no additional fields. It allows searching, insertion, deletion, deletemin, deletemax, splitting, joining, and many other operations, all with amortized logarithmic performance. Since the trees adapt to the sequence of requests, their performance on real access patterns is typically even better. Splay trees are described in a number of texts and papers [1,2,3,4,5]. \par The code here is adapted from simple top-down splay, at the bottom of page 669 of [3]. It can be obtained via anonymous ftp from spade.pc.cs.cmu.edu in directory /usr/sleator/public. \par The chief modification here is that the splay operation works even if the item being splayed is not in the tree, and even if the tree root of the tree is NULL. So the line: \par t = splay(i, t); \par causes it to search for item with key i in the tree rooted at t. If it's there, it is splayed to the root. If it isn't there, then the node put at the root is the last one before NULL that would have been reached in a normal binary search for i. (It's a neighbor of i in the tree.) This allows many other operations to be easily implemented. \par [1] "Fundamentals of data structures in C", Horowitz, Sahni, and Anderson-Freed, Computer Science Press, pp 542-547. \par [2] "Data Structures and Their Algorithms", Lewis and Denenberg, Harper Collins, 1991, pp 243-251. \par [3] "Self-adjusting Binary Search Trees" Sleator and Tarjan, JACM Volume 32, No 3, July 1985, pp 652-686. \par [4] "Data Structure and Algorithm Analysis", Mark Weiss, Benjamin Cummins, 1992, pp 119-130. \par [5] "Data Structures, Algorithms, and Performance", Derick Wood, Addison-Wesley, 1993, pp 367-375. \par The splay function is based on one written by Daniel Sleator, which is released in the public domain. \author Graeme McKerrell \date Created On : Fri Jan 23 12:50:18 2004 \version TESTED */ /*--------------------------------------------------------------- HISTORY 7-Dec-2004 Graeme McKerrell Updated to use the "lub" prefix 27-Feb-2004 Graeme McKerrell updated to simplify node initialisation 9-Feb-2004 Graeme McKerrell updated to make the comparision function compare a "clientnode" and "key" Updated getkey() function to fill out a provides "key" from a "clientnode" 23-Jan-2004 Graeme McKerrell Initial version -------------------------------------------------------------- Copyright (C) 2004 3Com Corporation. All Rights Reserved. **************************************************************** */ #ifndef _lub_bintree_h #define _lub_bintree_h #include /**************************************************************** * TYPE DEFINITIONS **************************************************************** */ /** * This type represents a bintree "node". * Typically the client will have a "clientnode" structure which * contains it's data. A bintree "node" is made one of the data * elements of that structure. When the tree is initialised the * client provides the offset into the structure of the * "node" which is to be used for that tree. */ typedef struct lub_bintree_node_s lub_bintree_node_t; /** * CLIENTS MUSTN'T TOUCH THE CONTENTS OF THIS STRUCTURE */ struct lub_bintree_node_s { /** internal */ lub_bintree_node_t *left; /** internal */ lub_bintree_node_t *right; }; /** * This type defines a callback function which will compare two "keys" * with each other * * \param clientnode the client node to compare * \param clientkey the key to compare with a node * * \return * <0 if clientnode < clientkey; * 0 if clientnode == clientkey; * >0 if clientnode > clientkey */ typedef int lub_bintree_compare_fn(const void *clientnode, const void *clientkey); /** * This is used to size the key storage area for an opaque key. * If any client requires a greater storage size then this will need to * be increased. */ #define lub_bintree_MAX_KEY_STORAGE (200) /** * This is used to declare an opaque key structure * Typically a client would declare their own non-opaque structure * which they would fill out appropriately */ typedef struct lub_bintree_key_s lub_bintree_key_t; /** * CLIENTS MUSTN'T TOUCH THE CONTENTS OF THIS STRUCTURE */ struct lub_bintree_key_s { /** internal */ char storage[lub_bintree_MAX_KEY_STORAGE]; /** internal */ int magic; }; /** * This type defines a callback function which will convert a client's "node" * into a search "key" * * \param clientnode the node from which to derive a key * \param key a reference to the key to fill out * * \return * A "key" which corresponds the "node" in this view */ typedef void lub_bintree_getkey_fn(const void *clientnode, lub_bintree_key_t * key); /** * This type represents an binary tree instance */ typedef struct lub_bintree_s lub_bintree_t; /** * CLIENTS MUSTN'T TOUCH THE CONTENTS OF THIS STRUCTURE */ struct lub_bintree_s { /** internal */ lub_bintree_node_t *root; /** internal */ size_t node_offset; /** internal */ lub_bintree_compare_fn *compareFn; /** internal */ lub_bintree_getkey_fn *getkeyFn; }; /** * This is used to perform iterations of a tree */ typedef struct lub_bintree_iterator_s lub_bintree_iterator_t; /** * CLIENTS MUSTN'T TOUCH THE CONTENTS OF THIS STRUCTURE */ struct lub_bintree_iterator_s { /** internal */ lub_bintree_t *tree; /** internal */ lub_bintree_key_t key; }; /**************************************************************** * BINTREE OPERATIONS **************************************************************** */ /** * This operation initialises an instance of a binary tree. * * \pre none * * \post The tree is ready to have client nodes inserted. */ extern void lub_bintree_init( /** * the "tree" instance to initialise */ lub_bintree_t * tree, /** * the offset of the bintree "node" structure within the * "clientnode" structure. This is typically passed * using the offsetof() macro. */ size_t node_offset, /** * a comparison function for comparing a "clientnode" * with a "clientkey" */ lub_bintree_compare_fn compareFn, /** * a function which will fill out a "key" from a clientnode */ lub_bintree_getkey_fn getkeyFn); /** * This operation is called to initialise a "clientnode" ready for * insertion into a tree. This is only required once after the memory * for a node has been allocated. * * \pre none * * \post The node is ready to be inserted into a tree. */ extern void lub_bintree_node_init( /** * the bintree node to initialise */ lub_bintree_node_t * node); /***************************************** * NODE MANIPULATION OPERATIONS ***************************************** */ /** * This operation adds a client node to the specified tree. * * \pre The tree must be initialised * \pre The clientnode must be initialised * * \return * 0 if the "clientnode" is added correctly to the tree. * If another "clientnode" already exists in the tree with the same key, then * -1 is returned, and the tree remains unchanged. * * \post If the bintree "node" is already part of a tree, then an * assert will fire. */ extern int lub_bintree_insert( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree, /** * a pointer to a client node. NB the tree can find the * necessary lub_BintreeNodeT from it's stored offset. */ void *clientnode); /** * This operation removes a "clientnode" from the specified "tree" * * \pre The tree must be initialised * \pre The clientnode must be initialised * * \post The "clientnode" will no longer be part of the specified tree, and will be * made available for re-insertion * \post If the clientnode is not present in the specified tree, then an * assert will fire. */ extern void lub_bintree_remove( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree, /** * the node to remove */ void *clientnode); /***************************************** * NODE RETRIEVAL OPERATIONS ***************************************** */ /** * This operation returns the first "clientnode" present in the specified "tree" * * \pre The tree must be initialised * * \return * "clientnode" instance or NULL if no nodes are present in this tree. */ extern void *lub_bintree_findfirst( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree); /** * This operation returns the last "clientnode" present in the specified "tree" * * \pre The tree must be initialised * * \return * "clientnode" instance or NULL if no nodes are present in this tree. */ extern void *lub_bintree_findlast( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree); /** * This operation searches the specified "tree" for a "clientnode" which matches the * specified "key" * * \pre The tree must be initialised * * \return * "clientnode" instance or NULL if no node is found. */ extern void *lub_bintree_find( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree, /** * the "key" to search with */ const void *key); /** * This operation searches the specified "tree" for a "clientnode" which is * the one which logically follows the specified "key" * * A "clientnode" with the specified "key" doesn't need to be in the tree. * * \pre The tree must be initialised * * \return * "clientnode" instance or NULL if no node is found. */ extern void *lub_bintree_findnext( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree, /** * the "key" to search with */ const void *key); /** * This operation searches the specified "tree" for a "clientnode" which is * the one which logically preceeds the specified "key" * * A "clientnode" with the specified "key" doesn't need to be in the tree. * * \pre The tree must be initialised * * \return * "clientnode" instance or NULL if no node is found. */ extern void *lub_bintree_findprevious( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree, /** * the "key" to search with */ const void *key); /***************************************** * ITERATION OPERATIONS ***************************************** */ /** * This operation initialises an iterator. This can then be * subsequently used for iterating through a tree. This will work * even if the "clientnode" which defined the current iterator has been * removed before the next iterator operation. * * \pre The tree must be initialised * \pre The clientnode must be initialised and valid at the time of this call * * \post The interator instance will be updated to reference the position in the tree for the clientnode. */ extern void lub_bintree_iterator_init( /** * the iterator instance to initialise */ lub_bintree_iterator_t * iter, /** * the tree to associate with this iterator */ lub_bintree_t * tree, /** * the starting point for the iteration */ const void *clientnode); /** * This operation returns the next "clientnode" in an iteration. * * \pre The interator instance must have been initialised * * \return * "clientnode" instance or NULL if the iteration has reached the end of the * tree. * * \post The interator instance will be updated to reference the position in the tree for the returned value. */ extern void *lub_bintree_iterator_next( /** * the iterator instance to invoke this operation upon. */ lub_bintree_iterator_t * iter); /** * This operation returns the previous "clientnode" in an iteration. * * \pre The interator instance must have been initialised * * \return * "clientnode" instance or NULL if the iteration has reached the beginning * of the tree. * * \post The interator instance will be updated to reference the position in the tree for the returned value. */ extern void *lub_bintree_iterator_previous( /** * the iterator instance to invoke this operation upon. */ lub_bintree_iterator_t * iter); /** * This operation dumps the node list of the specified tree to stdout * * \pre The tree must be initialised * * \post The structure of the tree will be unaltered. */ extern void lub_bintree_dump( /** * the "tree" instance to invoke this operation upon */ lub_bintree_t * tree); #endif /* _lub_bintree_h */ /** @} */