2 Andersson tree library
\r
4 > Created (Julienne Walker): September 10, 2005
\r
5 > Corrections (James Bucanek): April 10, 2006
\r
6 1) Typo in jsw_aerase:
\r
7 up != 0 should be top != 0
\r
8 2) Bug in jsw_aerase:
\r
9 skew ( path[top] ) should be skew ( up )
\r
10 split ( path[top] ) should be split ( up )
\r
11 3) Bug in skew and split macros:
\r
12 Condition should test for nil
\r
13 4) Bug in jsw_aerase:
\r
14 Search for successor should save the path
\r
16 #include "jsw_atree.h"
\r
28 #ifndef HEIGHT_LIMIT
\r
29 #define HEIGHT_LIMIT 64 /* Tallest allowable tree */
\r
32 typedef struct jsw_anode {
\r
33 int level; /* Horizontal level for balance */
\r
34 void *data; /* User-defined content */
\r
35 struct jsw_anode *link[2]; /* Left (0) and right (1) links */
\r
39 jsw_anode_t *root; /* Top of the tree */
\r
40 jsw_anode_t *nil; /* End of tree sentinel */
\r
41 cmp_f cmp; /* Compare two items */
\r
42 dup_f dup; /* Clone an item (user-defined) */
\r
43 rel_f rel; /* Destroy an item (user-defined) */
\r
44 size_t size; /* Number of items (user-defined) */
\r
48 jsw_atree_t *tree; /* Paired tree */
\r
49 jsw_anode_t *it; /* Current node */
\r
50 jsw_anode_t *path[HEIGHT_LIMIT]; /* Traversal path */
\r
51 size_t top; /* Top of stack */
\r
54 /* Remove left horizontal links */
\r
55 #define skew(t) do { \
\r
56 if ( t->link[0]->level == t->level && t->level != 0 ) { \
\r
57 jsw_anode_t *save = t->link[0]; \
\r
58 t->link[0] = save->link[1]; \
\r
59 save->link[1] = t; \
\r
64 /* Remove consecutive horizontal links */
\r
65 #define split(t) do { \
\r
66 if ( t->link[1]->link[1]->level == t->level && t->level != 0 ) { \
\r
67 jsw_anode_t *save = t->link[1]; \
\r
68 t->link[1] = save->link[0]; \
\r
69 save->link[0] = t; \
\r
75 static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )
\r
77 jsw_anode_t *rn = (jsw_anode_t *)malloc ( sizeof *rn );
\r
83 rn->data = tree->dup ( data );
\r
84 rn->link[0] = rn->link[1] = tree->nil;
\r
89 jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )
\r
91 jsw_atree_t *rt = (jsw_atree_t *)malloc ( sizeof *rt );
\r
96 /* Initialize sentinel */
\r
97 rt->nil = (jsw_anode_t *)malloc ( sizeof *rt->nil );
\r
98 if ( rt->nil == NULL ) {
\r
103 rt->nil->data = NULL; /* Simplifies some ops */
\r
104 rt->nil->level = 0;
\r
105 rt->nil->link[0] = rt->nil->link[1] = rt->nil;
\r
107 /* Initialize tree */
\r
108 rt->root = rt->nil;
\r
117 void jsw_adelete ( jsw_atree_t *tree )
\r
119 jsw_anode_t *it = tree->root;
\r
122 /* Destruction by rotation */
\r
123 while ( it != tree->nil ) {
\r
124 if ( it->link[0] == tree->nil ) {
\r
126 save = it->link[1];
\r
127 tree->rel ( it->data );
\r
132 save = it->link[0];
\r
133 it->link[0] = save->link[1];
\r
134 save->link[1] = it;
\r
140 /* Finalize destruction */
\r
141 free ( tree->nil );
\r
145 void *jsw_afind ( jsw_atree_t *tree, void *data )
\r
147 jsw_anode_t *it = tree->root;
\r
149 while ( it != tree->nil ) {
\r
150 int cmp = tree->cmp ( it->data, data );
\r
155 it = it->link[cmp < 0];
\r
158 /* nil->data == NULL */
\r
162 int jsw_ainsert ( jsw_atree_t *tree, void *data )
\r
164 if ( tree->root == tree->nil ) {
\r
165 /* Empty tree case */
\r
166 tree->root = new_node ( tree, data );
\r
167 if ( tree->root == tree->nil )
\r
171 jsw_anode_t *it = tree->root;
\r
172 jsw_anode_t *path[HEIGHT_LIMIT];
\r
175 /* Find a spot and save the path */
\r
178 dir = tree->cmp ( it->data, data ) < 0;
\r
180 if ( it->link[dir] == tree->nil )
\r
183 it = it->link[dir];
\r
186 /* Create a new item */
\r
187 it->link[dir] = new_node ( tree, data );
\r
188 if ( it->link[dir] == tree->nil )
\r
191 /* Walk back and rebalance */
\r
192 while ( --top >= 0 ) {
\r
195 dir = path[top - 1]->link[1] == path[top];
\r
197 skew ( path[top] );
\r
198 split ( path[top] );
\r
200 /* Fix the parent */
\r
202 path[top - 1]->link[dir] = path[top];
\r
204 tree->root = path[top];
\r
213 int jsw_aerase ( jsw_atree_t *tree, void *data )
\r
215 if ( tree->root == tree->nil )
\r
218 jsw_anode_t *it = tree->root;
\r
219 jsw_anode_t *path[HEIGHT_LIMIT];
\r
220 int top = 0, dir, cmp;
\r
222 /* Find node to remove and save path */
\r
226 if ( it == tree->nil )
\r
229 cmp = tree->cmp ( it->data, data );
\r
234 it = it->link[dir];
\r
237 /* Remove the found node */
\r
238 if ( it->link[0] == tree->nil
\r
239 || it->link[1] == tree->nil )
\r
241 /* Single child case */
\r
242 int dir2 = it->link[0] == tree->nil;
\r
244 /* Unlink the item */
\r
246 path[top - 1]->link[dir] = it->link[dir2];
\r
248 tree->root = it->link[1];
\r
250 tree->rel ( it->data );
\r
254 /* Two child case */
\r
255 jsw_anode_t *heir = it->link[1];
\r
256 jsw_anode_t *prev = it;
\r
258 while ( heir->link[0] != tree->nil ) {
\r
259 path[top++] = prev = heir;
\r
260 heir = heir->link[0];
\r
264 Order is important!
\r
265 (free item, replace item, free heir)
\r
267 tree->rel ( it->data );
\r
268 it->data = heir->data;
\r
269 prev->link[prev == it] = heir->link[1];
\r
273 /* Walk back up and rebalance */
\r
274 while ( --top >= 0 ) {
\r
275 jsw_anode_t *up = path[top];
\r
278 dir = path[top - 1]->link[1] == up;
\r
280 /* Rebalance (aka. black magic) */
\r
281 if ( up->link[0]->level < up->level - 1
\r
282 || up->link[1]->level < up->level - 1 )
\r
284 if ( up->link[1]->level > --up->level )
\r
285 up->link[1]->level = up->level;
\r
287 /* Order is important! */
\r
289 skew ( up->link[1] );
\r
290 skew ( up->link[1]->link[1] );
\r
292 split ( up->link[1] );
\r
295 /* Fix the parent */
\r
297 path[top - 1]->link[dir] = up;
\r
308 size_t jsw_asize ( jsw_atree_t *tree )
\r
313 jsw_atrav_t *jsw_atnew ( void )
\r
315 return malloc ( sizeof ( jsw_atrav_t ) );
\r
318 void jsw_atdelete ( jsw_atrav_t *trav )
\r
324 First step in traversal,
\r
325 handles min and max
\r
327 static void *start ( jsw_atrav_t *trav,
\r
328 jsw_atree_t *tree, int dir )
\r
331 trav->it = tree->root;
\r
334 /* Build a path to work with */
\r
335 if ( trav->it != tree->nil ) {
\r
336 while ( trav->it->link[dir] != tree->nil ) {
\r
337 trav->path[trav->top++] = trav->it;
\r
338 trav->it = trav->it->link[dir];
\r
342 /* Could be nil, but nil->data == NULL */
\r
343 return trav->it->data;
\r
347 Subsequent traversal steps,
\r
348 handles ascending and descending
\r
350 static void *move ( jsw_atrav_t *trav, int dir )
\r
352 jsw_anode_t *nil = trav->tree->nil;
\r
354 if ( trav->it->link[dir] != nil ) {
\r
355 /* Continue down this branch */
\r
356 trav->path[trav->top++] = trav->it;
\r
357 trav->it = trav->it->link[dir];
\r
359 while ( trav->it->link[!dir] != nil ) {
\r
360 trav->path[trav->top++] = trav->it;
\r
361 trav->it = trav->it->link[!dir];
\r
365 /* Move to the next branch */
\r
369 if ( trav->top == 0 ) {
\r
375 trav->it = trav->path[--trav->top];
\r
376 } while ( last == trav->it->link[dir] );
\r
379 /* Could be nil, but nil->data == NULL */
\r
380 return trav->it->data;
\r
383 void *jsw_atfirst ( jsw_atrav_t *trav, jsw_atree_t *tree )
\r
385 return start ( trav, tree, 0 ); /* Min value */
\r
388 void *jsw_atlast ( jsw_atrav_t *trav, jsw_atree_t *tree )
\r
390 return start ( trav, tree, 1 ); /* Max value */
\r
393 void *jsw_atnext ( jsw_atrav_t *trav )
\r
395 return move ( trav, 1 ); /* Toward larger items */
\r
398 void *jsw_atprev ( jsw_atrav_t *trav )
\r
400 return move ( trav, 0 ); /* Toward smaller items */
\r