fb4cc9f7c8e7c15ad68d0fa35f48e30846ac4af1
[tprouty/samba.git] / source / ubiqx / ubi_SplayTree.c
1 /* ========================================================================== **
2  *                              ubi_SplayTree.c
3  *
4  *  Copyright (C) 1993-1995 by Christopher R. Hertel
5  *
6  *  Email: crh@ubiqx.mn.org
7  * -------------------------------------------------------------------------- **
8  *
9  *  This module implements "splay" trees.  Splay trees are binary trees
10  *  that are rearranged (splayed) whenever a node is accessed.  The
11  *  splaying process *tends* to make the tree bushier (improves balance),
12  *  and the nodes that are accessed most frequently *tend* to be closer to
13  *  the top.
14  *
15  *  References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
16  *              Robert Tarjan.  Journal of the Association for Computing
17  *              Machinery Vol 32, No. 3, July 1985 pp. 652-686
18  *
19  * -------------------------------------------------------------------------- **
20  *
21  *  This library is free software; you can redistribute it and/or
22  *  modify it under the terms of the GNU Library General Public
23  *  License as published by the Free Software Foundation; either
24  *  version 2 of the License, or (at your option) any later version.
25  *
26  *  This library is distributed in the hope that it will be useful,
27  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  *  Library General Public License for more details.
30  *
31  *  You should have received a copy of the GNU Library General Public
32  *  License along with this library; if not, write to the Free
33  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34  *
35  * -------------------------------------------------------------------------- **
36  *
37  * Log: ubi_SplayTree.c,v
38  * Revision 3.0  1997/12/08 05:32:28  crh
39  * This is a new major revision level because of a redesign of the handling
40  * of the pointers in the ubi_trNode structure.  See ubi_BinTree for more
41  * info.
42  *
43  * Revision 2;  1995/02/27 - 1997/12/07:
44  * Major changes: added the function ubi_sptSplay().
45  *
46  * Revision 1; 93/10/15 - 95/02/27:
47  * Added the ubi_tr defines.  See ubi_BinTree.h for more info.
48  *
49  * Revision 0.0  93/04/21  23:05:52  CRH
50  * Initial version, written by Christopher R. Hertel.
51  * This module implements Splay Trees using the ubi_BinTree module as a basis.
52  *
53  * ========================================================================== **
54  */
55
56 #include <stdlib.h>        /* Defines NULL for us.                */
57 #include "ubi_SplayTree.h" /* Header for THIS module.             */
58
59 /* ========================================================================== **
60  * Static data.
61  */
62
63 static char ModuleID[] = "ubi_SplayTree\n\
64 \tRevision: 3.0\n\
65 \tDate: 1997/12/08 05:32:28\n\
66 \tAuthor: crh\n";
67
68
69 /* ========================================================================== **
70  * Private functions...
71  */
72
73 static void Rotate( ubi_btNodePtr p )
74   /* ------------------------------------------------------------------------ **
75    * This function performs a single rotation, moving node *p up one level
76    * in the tree.
77    *
78    *  Input:    p - a pointer to an ubi_btNode in a tree.
79    *
80    *  Output:   None.
81    *
82    *  Notes:    This implements a single rotation in either direction (left
83    *            or right).  This is the basic building block of all splay
84    *            tree rotations.
85    * ------------------------------------------------------------------------ **
86    */
87   {
88   ubi_btNodePtr parentp;
89   ubi_btNodePtr tmp;
90   signed char   way;
91   signed char   revway;
92
93   parentp = p->Link[ubi_trPARENT];    /* Find parent. */
94
95   if( parentp )                 /* If no parent, then we're already the root. */
96     {
97     way     = p->gender;
98     revway  = ubi_trRevWay(way);
99     tmp     = p->Link[revway];
100
101     parentp->Link[way]  = tmp;
102     if( tmp )
103       {
104       tmp->Link[ubi_trPARENT] = parentp;
105       tmp->gender             = way;
106       }
107
108     tmp                   = parentp->Link[ubi_trPARENT];
109     p->Link[ubi_trPARENT] = tmp;
110     p->gender             = parentp->gender;
111     if( tmp )
112       tmp->Link[p->gender] = p;
113
114     parentp->Link[ubi_trPARENT] = p;
115     parentp->gender             = revway;
116     p->Link[revway]             = parentp;
117     }
118   } /* Rotate */
119
120 static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
121   /* ------------------------------------------------------------------------ **
122    * Move the node indicated by SplayWithMe to the root of the tree by
123    * splaying the tree.
124    *
125    *  Input:  SplayWithMe - A pointer to an ubi_btNode within a tree.
126    *
127    *  Output: A pointer to the root of the splay tree (i.e., the same as
128    *          SplayWithMe).
129    * ------------------------------------------------------------------------ **
130    */
131   {
132   ubi_btNodePtr parent;
133
134   while( (parent = SplayWithMe->Link[ubi_trPARENT]) )
135     {
136     if( parent->gender == SplayWithMe->gender )       /* Zig-Zig */
137       Rotate( parent );
138     else
139       {
140       if( ubi_trEQUAL != parent->gender )             /* Zig-Zag */
141         Rotate( SplayWithMe );
142       }
143     Rotate( SplayWithMe );                            /* Zig */
144     } 
145   return( SplayWithMe );
146   } /* Splay */
147
148 /* ========================================================================== **
149  * Exported utilities.
150  */
151
152 ubi_trBool ubi_sptInsert( ubi_btRootPtr  RootPtr,
153                           ubi_btNodePtr  NewNode,
154                           ubi_btItemPtr  ItemPtr,
155                           ubi_btNodePtr *OldNode )
156   /* ------------------------------------------------------------------------ **
157    * This function uses a non-recursive algorithm to add a new element to the
158    * splay tree.
159    *
160    *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
161    *                       the root of the tree to which NewNode is to be added.
162    *           NewNode  -  a pointer to an ubi_btNode structure that is NOT
163    *                       part of any tree.
164    *           ItemPtr  -  A pointer to the sort key that is stored within
165    *                       *NewNode.  ItemPtr MUST point to information stored
166    *                       in *NewNode or an EXACT DUPLICATE.  The key data
167    *                       indicated by ItemPtr is used to place the new node
168    *                       into the tree.
169    *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
170    *                       the tree, a duplicate node may be found.  If
171    *                       duplicates are allowed, then the new node will
172    *                       be simply placed into the tree.  If duplicates
173    *                       are not allowed, however, then one of two things
174    *                       may happen.
175    *                       1) if overwritting *is not* allowed, this
176    *                          function will return FALSE (indicating that
177    *                          the new node could not be inserted), and
178    *                          *OldNode will point to the duplicate that is
179    *                          still in the tree.
180    *                       2) if overwritting *is* allowed, then this
181    *                          function will swap **OldNode for *NewNode.
182    *                          In this case, *OldNode will point to the node
183    *                          that was removed (thus allowing you to free
184    *                          the node).
185    *                          **  If you are using overwrite mode, ALWAYS  **
186    *                          ** check the return value of this parameter! **
187    *                 Note: You may pass NULL in this parameter, the
188    *                       function knows how to cope.  If you do this,
189    *                       however, there will be no way to return a
190    *                       pointer to an old (ie. replaced) node (which is
191    *                       a problem if you are using overwrite mode).
192    *
193    *  Output:  a boolean value indicating success or failure.  The function
194    *           will return FALSE if the node could not be added to the tree.
195    *           Such failure will only occur if duplicates are not allowed,
196    *           nodes cannot be overwritten, AND a duplicate key was found
197    *           within the tree.
198    * ------------------------------------------------------------------------ **
199    */
200   {
201   ubi_btNodePtr OtherP;
202
203   if( !(OldNode) )
204     OldNode = &OtherP;
205
206   if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
207     {
208     RootPtr->root = Splay( NewNode );
209     return( ubi_trTRUE );
210     }
211
212   /* Splay the unreplacable, duplicate keyed, unique, old node. */
213   RootPtr->root = Splay( (*OldNode) );
214   return( ubi_trFALSE );
215   } /* ubi_sptInsert */
216
217 ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
218   /* ------------------------------------------------------------------------ **
219    * This function removes the indicated node from the tree.
220    *
221    *  Input:   RootPtr  -  A pointer to the header of the tree that contains
222    *                       the node to be removed.
223    *           DeadNode -  A pointer to the node that will be removed.
224    *
225    *  Output:  This function returns a pointer to the node that was removed
226    *           from the tree (ie. the same as DeadNode).
227    *
228    *  Note:    The node MUST be in the tree indicated by RootPtr.  If not,
229    *           strange and evil things will happen to your trees.
230    * ------------------------------------------------------------------------ **
231    */
232   {
233   ubi_btNodePtr p;
234
235   (void)Splay( DeadNode );                  /* Move dead node to root.        */
236   if( (p = DeadNode->Link[ubi_trLEFT]) )    /* If left subtree exists...      */
237     {
238     ubi_btNodePtr q = DeadNode->Link[ubi_trRIGHT];
239
240     p->Link[ubi_trPARENT] = NULL;           /* Left subtree node becomes root.*/
241     p->gender       = ubi_trPARENT;
242     p               = ubi_btLast( p );      /* Find rightmost left tree node..*/
243     p->Link[ubi_trRIGHT]  = q;              /* ...attach right tree.          */
244     if( q )
245       q->Link[ubi_trPARENT] = p;
246     RootPtr->root   = Splay( p );           /* Resplay at p.                  */
247     }
248   else
249     {
250     if( (p = DeadNode->Link[ubi_trRIGHT]) ) /* No left, but right subtree...  */
251       {                                     /* ...exists...                   */
252       p->Link[ubi_trPARENT] = NULL;         /* Right subtree root becomes...  */
253       p->gender       = ubi_trPARENT;       /* ...overall tree root.          */
254       RootPtr->root   = p;
255       }
256     else
257       RootPtr->root = NULL;                 /* No subtrees => empty tree.     */
258     }
259
260   (RootPtr->count)--;                       /* Decrement node count.          */
261   return( DeadNode );                       /* Return pointer to pruned node. */
262   } /* ubi_sptRemove */
263
264 ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
265                              ubi_btItemPtr FindMe,
266                              ubi_trCompOps CompOp )
267   /* ------------------------------------------------------------------------ **
268    * The purpose of ubi_btLocate() is to find a node or set of nodes given
269    * a target value and a "comparison operator".  The Locate() function is
270    * more flexible and (in the case of trees that may contain dupicate keys)
271    * more precise than the ubi_btFind() function.  The latter is faster,
272    * but it only searches for exact matches and, if the tree contains
273    * duplicates, Find() may return a pointer to any one of the duplicate-
274    * keyed records.
275    *
276    *  Input:
277    *     RootPtr  -  A pointer to the header of the tree to be searched.
278    *     FindMe   -  An ubi_btItemPtr that indicates the key for which to
279    *                 search.
280    *     CompOp   -  One of the following:
281    *                    CompOp     Return a pointer to the node with
282    *                    ------     ---------------------------------
283    *                   ubi_trLT - the last key value that is less
284    *                              than FindMe.
285    *                   ubi_trLE - the first key matching FindMe, or
286    *                              the last key that is less than
287    *                              FindMe.
288    *                   ubi_trEQ - the first key matching FindMe.
289    *                   ubi_trGE - the first key matching FindMe, or the
290    *                              first key greater than FindMe.
291    *                   ubi_trGT - the first key greater than FindMe.
292    *  Output:
293    *     A pointer to the node matching the criteria listed above under
294    *     CompOp, or NULL if no node matched the criteria.
295    *
296    *  Notes:
297    *     In the case of trees with duplicate keys, Locate() will behave as
298    *     follows:
299    *
300    *     Find:  3                       Find: 3
301    *     Keys:  1 2 2 2 3 3 3 3 3 4 4   Keys: 1 1 2 2 2 4 4 5 5 5 6
302    *                  ^ ^         ^                   ^ ^
303    *                 LT EQ        GT                 LE GE
304    *
305    *     That is, when returning a pointer to a node with a key that is LESS
306    *     THAN the target key (FindMe), Locate() will return a pointer to the
307    *     LAST matching node.
308    *     When returning a pointer to a node with a key that is GREATER
309    *     THAN the target key (FindMe), Locate() will return a pointer to the
310    *     FIRST matching node.
311    *
312    *  See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
313    * ------------------------------------------------------------------------ **
314    */
315   {
316   ubi_btNodePtr p;
317
318   p = ubi_btLocate( RootPtr, FindMe, CompOp );
319   if( p )
320     RootPtr->root = Splay( p );
321   return( p );
322   } /* ubi_sptLocate */
323
324 ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
325                            ubi_btItemPtr FindMe )
326   /* ------------------------------------------------------------------------ **
327    * This function performs a non-recursive search of a tree for any node
328    * matching a specific key.
329    *
330    *  Input:
331    *     RootPtr  -  a pointer to the header of the tree to be searched.
332    *     FindMe   -  a pointer to the key value for which to search.
333    *
334    *  Output:
335    *     A pointer to a node with a key that matches the key indicated by
336    *     FindMe, or NULL if no such node was found.
337    *
338    *  Note:   In a tree that allows duplicates, the pointer returned *might
339    *          not* point to the (sequentially) first occurance of the
340    *          desired key.  In such a tree, it may be more useful to use
341    *          ubi_sptLocate().
342    * ------------------------------------------------------------------------ **
343    */
344   {
345   ubi_btNodePtr p;
346
347   p = ubi_btFind( RootPtr, FindMe );
348   if( p )
349     RootPtr->root = Splay( p );
350   return( p );
351   } /* ubi_sptFind */
352
353 void ubi_sptSplay( ubi_btRootPtr RootPtr,
354                    ubi_btNodePtr SplayMe )
355   /* ------------------------------------------------------------------------ **
356    *  This function allows you to splay the tree at a given node, thus moving
357    *  the node to the top of the tree.
358    *
359    *  Input:
360    *     RootPtr  -  a pointer to the header of the tree to be splayed.
361    *     SplayMe  -  a pointer to a node within the tree.  This will become
362    *                 the new root node.
363    *  Output: None.
364    *
365    *  Notes:  This is an uncharacteristic function for this group of modules
366    *          in that it provides access to the internal balancing routines,
367    *          which would normally be hidden.
368    *          Splaying the tree will not damage it (assuming that I've done
369    *          *my* job), but there is overhead involved.  I don't recommend
370    *          that you use this function unless you understand the underlying
371    *          Splay Tree.
372    * ------------------------------------------------------------------------ **
373    */
374   {
375   RootPtr->root = Splay( SplayMe );
376   } /* ubi_sptSplay */
377
378 int ubi_sptModuleID( int size, char *list[] )
379   /* ------------------------------------------------------------------------ **
380    * Returns a set of strings that identify the module.
381    *
382    *  Input:  size  - The number of elements in the array <list>.
383    *          list  - An array of pointers of type (char *).  This array
384    *                  should, initially, be empty.  This function will fill
385    *                  in the array with pointers to strings.
386    *  Output: The number of elements of <list> that were used.  If this value
387    *          is less than <size>, the values of the remaining elements are
388    *          not guaranteed.
389    *
390    *  Notes:  Please keep in mind that the pointers returned indicate strings
391    *          stored in static memory.  Don't free() them, don't write over
392    *          them, etc.  Just read them.
393    * ------------------------------------------------------------------------ **
394    */
395   {
396   if( size > 0 )
397     {
398     list[0] = ModuleID;
399     if( size > 1 )
400       return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
401     return( 1 );
402     }
403   return( 0 );
404   } /* ubi_sptModuleID */
405
406 /* ================================ The End ================================= */