1 #define _POSIX_C_SOURCE 200809L
5 > Created (Julienne Walker): September 10, 2005
6 > Corrections (James Bucanek): April 10, 2006
8 up != 0 should be top != 0
10 skew ( path[top] ) should be skew ( up )
11 split ( path[top] ) should be split ( up )
12 3) Bug in skew and split macros:
13 Condition should test for nil
15 Search for successor should save the path
24 #define HEIGHT_LIMIT 64 /* Tallest allowable tree */
27 typedef struct jsw_anode {
28 int level; /* Horizontal level for balance */
29 void *data; /* User-defined content */
30 struct jsw_anode *link[2]; /* Left (0) and right (1) links */
34 jsw_anode_t *root; /* Top of the tree */
35 jsw_anode_t *nil; /* End of tree sentinel */
36 cmp_f cmp; /* Compare two items */
37 dup_f dup; /* Clone an item (user-defined) */
38 rel_f rel; /* Destroy an item (user-defined) */
39 size_t size; /* Number of items (user-defined) */
43 jsw_atree_t *tree; /* Paired tree */
44 jsw_anode_t *it; /* Current node */
45 jsw_anode_t *path[HEIGHT_LIMIT]; /* Traversal path */
46 size_t top; /* Top of stack */
49 /* Remove left horizontal links */
50 #define skew(t) do { \
51 if ( t->link[0]->level == t->level && t->level != 0 ) { \
52 jsw_anode_t *save = t->link[0]; \
53 t->link[0] = save->link[1]; \
59 /* Remove consecutive horizontal links */
60 #define split(t) do { \
61 if ( t->link[1]->link[1]->level == t->level && t->level != 0 ) { \
62 jsw_anode_t *save = t->link[1]; \
63 t->link[1] = save->link[0]; \
70 int jsw_afind_strcmp(const void *a, const void *b) {
74 static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )
76 jsw_anode_t *rn = malloc ( sizeof *rn );
82 rn->data = tree->dup ( data );
83 rn->link[0] = rn->link[1] = tree->nil;
88 jsw_atree_t *jsw_anew_str(void) {
89 return jsw_anew(jsw_afind_strcmp, (dup_f)strdup, (rel_f)free);
92 jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )
94 jsw_atree_t *rt = malloc ( sizeof *rt );
99 /* Initialize sentinel */
100 rt->nil = malloc ( sizeof *rt->nil );
101 if ( rt->nil == NULL ) {
106 rt->nil->data = NULL; /* Simplifies some ops */
108 rt->nil->link[0] = rt->nil->link[1] = rt->nil;
110 /* Initialize tree */
120 void jsw_adelete(jsw_atree_t *tree) {
131 /* Destruction by rotation */
132 while ( it != tree->nil ) {
133 if ( it->link[0] == tree->nil ) {
136 tree->rel ( it->data );
142 it->link[0] = save->link[1];
149 /* Finalize destruction */
154 void *jsw_afind ( jsw_atree_t *tree, void *data) {
155 jsw_anode_t *it = tree->root;
158 while ( it != tree->nil ) {
159 cmp = tree->cmp(it->data, data);
164 it = it->link[cmp < 0];
167 /* nil->data == NULL */
171 int jsw_ainsert ( jsw_atree_t *tree, void *data )
173 if ( tree->root == tree->nil ) {
174 /* Empty tree case */
175 tree->root = new_node ( tree, data );
176 if ( tree->root == tree->nil )
180 jsw_anode_t *it = tree->root;
181 jsw_anode_t *path[HEIGHT_LIMIT];
184 /* Find a spot and save the path */
187 dir = tree->cmp ( it->data, data ) < 0;
189 if ( it->link[dir] == tree->nil )
195 /* Create a new item */
196 it->link[dir] = new_node ( tree, data );
197 if ( it->link[dir] == tree->nil )
200 /* Walk back and rebalance */
201 while ( --top >= 0 ) {
204 dir = path[top - 1]->link[1] == path[top];
211 path[top - 1]->link[dir] = path[top];
213 tree->root = path[top];
222 int jsw_aerase ( jsw_atree_t *tree, void *data )
224 if ( tree->root == tree->nil )
227 jsw_anode_t *it = tree->root;
228 jsw_anode_t *path[HEIGHT_LIMIT];
229 int top = 0, dir, cmp;
231 /* Find node to remove and save path */
235 if ( it == tree->nil )
238 cmp = tree->cmp ( it->data, data );
246 /* Remove the found node */
247 if ( it->link[0] == tree->nil
248 || it->link[1] == tree->nil )
250 /* Single child case */
251 int dir2 = it->link[0] == tree->nil;
253 /* Unlink the item */
255 path[top - 1]->link[dir] = it->link[dir2];
257 tree->root = it->link[1];
259 tree->rel ( it->data );
264 jsw_anode_t *heir = it->link[1];
265 jsw_anode_t *prev = it;
267 while ( heir->link[0] != tree->nil ) {
268 path[top++] = prev = heir;
269 heir = heir->link[0];
274 (free item, replace item, free heir)
276 tree->rel ( it->data );
277 it->data = heir->data;
278 prev->link[prev == it] = heir->link[1];
282 /* Walk back up and rebalance */
283 while ( --top >= 0 ) {
284 jsw_anode_t *up = path[top];
287 dir = path[top - 1]->link[1] == up;
289 /* Rebalance (aka. black magic) */
290 if ( up->link[0]->level < up->level - 1
291 || up->link[1]->level < up->level - 1 )
293 if ( up->link[1]->level > --up->level )
294 up->link[1]->level = up->level;
296 /* Order is important! */
298 skew ( up->link[1] );
299 skew ( up->link[1]->link[1] );
301 split ( up->link[1] );
306 path[top - 1]->link[dir] = up;
317 size_t jsw_asize ( jsw_atree_t *tree )
322 jsw_atrav_t *jsw_atnew ( void )
324 return malloc ( sizeof ( jsw_atrav_t ) );
327 void jsw_atdelete ( jsw_atrav_t *trav )
333 First step in traversal,
336 static void *start ( jsw_atrav_t *trav,
337 jsw_atree_t *tree, int dir )
340 trav->it = tree->root;
343 /* Build a path to work with */
344 if ( trav->it != tree->nil ) {
345 while ( trav->it->link[dir] != tree->nil ) {
346 trav->path[trav->top++] = trav->it;
347 trav->it = trav->it->link[dir];
351 /* Could be nil, but nil->data == NULL */
352 return trav->it->data;
356 Subsequent traversal steps,
357 handles ascending and descending
359 static void *move ( jsw_atrav_t *trav, int dir )
361 jsw_anode_t *nil = trav->tree->nil;
363 if ( trav->it->link[dir] != nil ) {
364 /* Continue down this branch */
365 trav->path[trav->top++] = trav->it;
366 trav->it = trav->it->link[dir];
368 while ( trav->it->link[!dir] != nil ) {
369 trav->path[trav->top++] = trav->it;
370 trav->it = trav->it->link[!dir];
374 /* Move to the next branch */
378 if ( trav->top == 0 ) {
384 trav->it = trav->path[--trav->top];
385 } while ( last == trav->it->link[dir] );
388 /* Could be nil, but nil->data == NULL */
389 return trav->it->data;
392 void *jsw_atfirst ( jsw_atrav_t *trav, jsw_atree_t *tree )
394 return start ( trav, tree, 0 ); /* Min value */
397 void *jsw_atlast ( jsw_atrav_t *trav, jsw_atree_t *tree )
399 return start ( trav, tree, 1 ); /* Max value */
402 void *jsw_atnext ( jsw_atrav_t *trav )
404 return move ( trav, 1 ); /* Toward larger items */
407 void *jsw_atprev ( jsw_atrav_t *trav )
409 return move ( trav, 0 ); /* Toward smaller items */